Historian: Because Please Stop Deleting My Bash History
undertitled.com
undertitled.com
With a git merge driver [3] the history database can be kept in source control and shared between hosts.
Queries look a bit like
$ histdb blah
time ses dir cmd
09/02 24 ~ ogr2ogr temp/blah.shp 'WFS:http://environment.data.gov.uk/ds/wfs?SERVICE=WFS&INTERFACE=ENVIRONMENTWFS&VERSION=1.0.0&LC=3000000000000000000000000000000'
09/02 24 ~/temp cd blah.shp
15/02 146 ~/.emacs.d git commit -am "blah"
22/02 175 ~ test="asdf/blah.shp"
09:48 743 ~/.histdb hist blah
The sess column here is a unique (per-host) session number which means it can recreate any transcript with a suitable query; if I ran histdb -s 24 it would produce the whole session containing the top two results above, including directory history.[1] https://github.com/larkery/zsh/blob/master/sqlite-history.zs... [2] https://github.com/larkery/zsh/blob/master/self-insert-overr... [3] https://github.com/larkery/zsh/blob/master/histdb-merge.zsh
Also your [3] link is broken.
https://github.com/tarjoilija/zgen
Edit: any way to import the existing .zsh_history?
I don't use a zsh package manager and don't really want to learn one, but if you can tell me the minimal glue I need to add to make these files into a package I will happily duplicate them into another repository and keep them up to date there. Ed.: https://github.com/larkery/zsh-histdb
I haven't done anything to import the history file because some of the information is missing so it would be a bit untidy. You could do something like
history 0 | while read -r num line; do
zshaddhistory "$line"
done
This will make bogus entries where the history includes newlines; you could probably use a loop on history number instead, or do something in the while loop to accumulate split lines by looking at "$num" and seeing if it goes up.$ wc -l .bash_history 0
I think there is some context missing here... Why is your .bash_history getting cropped? Was there a change in some default configuration of your Terminal app on update perhaps?
On a side-note I really think fish-shell really got history-recall and completion right, which is really the one thing that keeps me using it even if I still script in bash.
http://unix.stackexchange.com/a/88856
> When closing multiple bash instances at the same time, there is a known race condition that may cause the history to be cleared.
Also, on pentests the ~/.bash_history file is literally the first thing we look at. It's lovely: in an instant, you know exactly which files on the system are important, why they're being used, and what the high-priority targets might be for pivoting to a different box. In some cases it cuts hours off the job. So to keep hackers happy, please don't delete your bash history on production servers.
In a perfect world most things are done via config management, leaving only debugging to be done on prod servers, which should be transient in nature.
In the real world, prod servers should still get treated as transiently as possible.
Authenticated wiki or documentation repo is fine. Automation for tasks, external log shopping, error collection, separate db interface even better. Complete mirror of production in a separate, debuggable environment is the bees knees. But they all take time to achieve. In the meantime, with one or two VMs running your business, I bet you're glad to have a command history, especially if something's down at 3am :-) It all depends on your size and system.
I mean, it's really clever talking like a mafia enforcer making vague threats but everyone here is treating you respectfully and you're not responding in kind. It's not cool, man. If you don't feel like engaging, don't.
The hassle of not having a history file every day is a much bigger cost than having it on an already pwned machine, isn't it?
Stop being an ass, that's why most people don't listen to security experts, instead of educating people in a kind way and making the world more secure most of you like to live on your high ivory towers with snark comments, passive-aggressiveness doesn't help anyone or any discourse.
Please, learn some social skills.
You have already pwned the machine, what disabling history is gonna do to save someone's ass after that?
The hassle of not having a history file every day is a much bigger cost than having it on an already pwned machine, isn't it?
This is why most people don't listen to security experts, instead of educating people in a kind way and making the world more secure most of you like to just point out how bad we are.
Or passed in a password as an argument to any programs? (e.g. mysql -uusername -ppassword -hprod.db.com)
Plus, if the commands are important as they appear to be (with the need to be referenced days or weeks later), assuming they don't contain passwords, why not put them into a protected team wiki (or a private Github Gist)?
As an attacker, your goal is to get the most amount of privilege and credentials in a brief amount of time without being detected while it's happening. So you grab .bash_history, .bashrc, .bash_profile, .aws/credentials, .ssh/config, .ssh/id_*, .ssh/known_hosts, .pgpass, .psql_history, .mysql_history, .gitconfig, and then get out before a second has even elasped.
As a target, your goal is to limit the blast radius as much as possible, and by following certain practices, if/when you are compromised you can accurately state what the attackers could or could not have had access to.
This isn't about being 100% hackproof, it's about limiting the damage when you are hacked.
If a server is 'compromised' I delete it from the stack, spin up another and provision it all within 60's. The goal is not preventing being hacked, its being in a position where it does not matter.
If your server is compromised, you shouldn't be back in business in 60s. You need to rotate EVERY secret on that instance and everything it connected to. Your main database that coordinates 50 servers? One of the 50 gets compromised, you need to change the pw on all 50. That should include 3rd party API keys and other fun stuff too.
And PS all of that needs to happen _after_ you find out how they got in.
Of course. Promptly followed by export HISTFILE=
Thank you! I didn't realize I could do that (:
With the history file already there, you don't have to wait for it to populate.
Restrictions on what people want to do are always a bad idea. Removing history where people actually use it means that you'll get shadow IT. That means snippets of commands in home directories, "manual" history equivalents, and expect scripts with passwords embedded shared between teams.
Instead of trying to restrict what people want, you can make it easier - spend time automating tasks, providing simple interface to need information, and make sure you can take hosts out of live system for debugging (and then rebuild instead of returning). If there's important stuff in the history file, that means there's a need for history access. Working on solving that will give you more benefits than killing history files.
I really wish it weren't, and a decent penetration tester will know what to do with the known hosts machine on a machine with IP 192.168.0.83 anyway (which is the common case for me), or can just feed it to one of those botnets that ssh's to every public IPv4 address on earth every 60 seconds or so.
But, like password restrictions, the important thing is is inconveniences everyone, so it looks like the security team is doing something.
Sure, I might fail a pentest, but what I'm concerned with is protecting against actual real-world attacks without disrupting business operations. Protecting against a pentest just looks good on the pentester's checklist, what really matters is "did we get hacked?".
A good penetration tester will look around a bit with their elevated privileges and maybe find some other things and write those up too.
A great penetration tester will own everything, document how they did it initially, use their elevated access to gain an advanced understanding of your environment, document this understanding, and find as many nooks and crannies as they can in their assessment time frame. They will document these issues realistically and label things like auditing and clearing bash_history as defense in depth.
But the parent also has a point. These little things are accelerators on a pen test. No they aren't going to be the thing that gets you owned.
To be fair I have seen plenty of pen testers that wield findings like this as a hammer making it seem very important while missing the forest (for the tree in front of them) so to speak. Also, the best question probably isn't "did we get hacked?" but "how badly are we hacked right now?", because you are certainly "hacked", just maybe not at a nuclear melt down level.
The idea of any security system should be to compliment normal business operations, not to hinder them.
#soon
http://wiki.bash-hackers.org/syntax/shellvars#histtimeformat
I'm not an historian, but most of my friends are somewhere in the humanities fields, and two of them are historians.
But I quit the academic path due to economic reasons, i.e bad pay, and needing to apply to grants. I think unless you're explicitly acknowledged as an engineer/programmer it's hard to get anything remotely competitive.
export PROMPT_COMMAND='if [ "$(id -u)" -ne 0 ]; then echo "$(date "+%Y-%m-%d.%H:%M:%S") $(pwd) $(history 1)" >> ~/.logs/bash-history-$(date "+%Y-%m-%d").log; fi'
Creates a daily log file of every command entered. Searching for anything is a simple grep command.
export PROMPT_COMMAND+='; if [ "$(id -u)" -ne 0 ]; then echo "$(date "+%Y-%m-%d.%H:%M:%S") $(pwd) $(history 1)" >> ~/.logs/bash-history-$(date "+%Y-%m-%d").log; fi'Nope, no cron. It basically takes your command, and appends (creates if it does not exist) it to a file based on the current date.
And run
mkdir ~/.logs
because that's where the logs are stored.He makes an extraordinary effort to maintain his bash history whereas I jump through hoops to delete my history (on logout using a .bash_logout file).
I also set my browser to maintain no history, disable saving of chats in everything, delete caches wherever possible, and generally wish that apps and programs had an option to save zero information on exit!
If I want "history" beyond a session, I'll explicitly make a shell alias for a command that I want to remember, or make bookmark for a site I want to revisit, etc.
Furthermore, for many people, using the command line is part of their daily job. Not keeping a history and/or log, is akin to compiling your source code, keeping the binary and deleting the source.
If there are certain things you don't want in your bash history, use the ignorespace capability and explicitly do not store them.
If you write it to disk, it could available on the disk via an undelete tool or via a backup - which is a concern if you ever accidentally paste a password onto the command line.
Now paranoia is a scale, and we are, I'm sure, gaussianly distributed on it. I approve of this, as it provides a nice safeguard against extinction events against the hump in the middle. But man, I glad AF I'm not on your side of the curve. That would suck.
Thanks for standing in the gap.
ln -sf /dev/null ~/.bash_history
!unset HISTFILE
export HISTFILE=/dev/null
in my .bashrc for 20 years. I just don't see the appeal of persistent history. And I've seen too many intrusion pastes where passwords and databases are pulled out of the bash history file.I still try to keep my site history available, but it's very awkward with the amount of non-family content that I visit. Oh well.
Also, https://support.mozilla.org/t5/Basic-Browsing/Awesome-Bar-Se..., last couple of paragraphs site hire to use the modifiers in address-bar search for those who don't know about that.
^ In this comment I explained how I just have all my bash history logged directly into SQLite.
Written in go, uses sqlite and can work locally or remotely. In the latter case you can send history from many accounts and search globally. Transport encryption is based on NaCl. One binary serves all roles.
Doesn't store other information than command line and time but this is what I need most of time.
The main pain point behind its creation was searching in history. There is a global flag (search in all accounts, -g), the wild card is SQL's wild card (%). Less frequently used but very helpful, content search (-A, -B, -C, like grep). Also regexp is supported though very rarely is needed.
My solution around this, is, when regexp is enabled, to query for all the history and then have Go perform the regexp search itself —the normal is to let SQLite perform the search.
Depending on your CPU and history size, you may need a couple seconds for the result. For example when the server process runs on an Atom processor and the history is about 150.000 lines long, a regexp search takes about 7 seconds. A normal search with a wildcard on the same machine and history database, needs only 1 second.
My point is that novice developers don't usually work with that size of data. And if they are working with that size of data, then both regex and performance are good things for them to learn :)
https://github.com/l0b0/tilde/blob/master/.bash_history
Git GUI plus a simple Makefile target to sort it is all the tooling necessary:
https://github.com/l0b0/tilde/blob/b16794f2ff209a6bc64813f02...
If someone put a gun on me and asked to give him my bash history, I'll probably do it but not before thinking twice.
I've also kept my bash history (well, more like my zsh history actually) for a few years and across a few re-installs now. I'm sure there's a few cleartext passwords in there (for nothing too important), a couple of dubious wget commands, all the videos I've ever watched (I use a CLI video player) and who knows what else.
Oh and a bunch of confidential work stuff, I'm sure. Now that I think about it, maybe I should delete it...
rsync --rsh='ssh -p 2020 -i ~/.ssh/host.pem'
--archive --human-readable --progress --verbose
host:/path /target # network transfer
In examples like the above, he appears to have sanitized things to be useful from the perspective of "How do I do X again?" -- very cool.I think you are very brave to make this document available to the world - it is not something i would like to do.
EDIT: I think of it like the browser history for your daily work.
EDIT 2: It seems quite a lot of people think it is a good idea to store their bash_history on github, who knew! google dork: "inurl:github.com intitle:bash_history"
This had a few advantages which might not be immediately apparent. The most obvious is that you remove the risk of leaking private or sensitive data.
The second is that searching your history is an anti-pattern. If there is a command you can't remember, or if there is a group of commands you need to accomplish a task, you should be writing shell scripts
My ~/bin folder has 104 files in it[0] and is in git, is available wherever I log in, whichever tty I have open and has a much better taxonomy than 'search for part of command' based on doing tasks. The same can't be said for history files.
[0] at its peak when I was a BSD and RHEL user it would have been more files but i've recently switched to Alpine.
Any command that starts with a space is still successful but will be discarded in bash history. As "internet is for porn" could be useful to delete any video viewer entry automatically. (Add some lines like: "alias vlc=' vlc'" in your .bashrc). History can be also configured to save only one copy of duplicated commands.
If you have a sensible or difficult to memorize command the best is to put it in a script, not in a db.
I also have a `~/.savedcommands` file that I save one-liners to with a comment at the end, and `C-s` at the prompt loads that file into Percol, so I can search these more easily than searching the entire shell history. `savelastcommand` saves the last command to this file, or `savecommand COMMAND` does the same thing.
$ shopt -s histappend
$ export HISTTIMEFORMAT="%F %T: "
$ export HISTCONTROL=ignoreboth
$ export HISTFILESIZE=-1
$ export HISTSIZE=-1
Also, maybe you should consider backing up ~/.bash_history occasionally?Oh yes.
I always keep my own history of every command I ever run. I've moved this from computer to computer. So I can look back years in the past and see what I've done.
case "$TERM" in
xterm*|rxvt*)
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD/$HOME/~}\007"; echo `date +"%b %e %Y %H:%M:%S"` $? \"`history 1|cut -c7-`\" in `pwd` >> ~/.audit'
;;
*)
;;
esacInstead I found this to add to my .bashrc:
pcmd='if [ "$(id -u)" -ne 0 ]; then echo "$(pwd) $(history 1)" >> ~/.logs/bash-history-$(date "+%Y-%m-%d").log; fi'
PROMPT_COMMAND="$PROMPT_COMMAND;$pcmd"
It keeps all commands from all open shells in dated log files that I can grep through when Ctrl+R fails me.Just be aware that if someone hacks into your PC they can see every command you have ever run, including any passwords accidentally pasted.
shopt -s histappend
HISTCONTROL=ignoredups:erasedups
PROMPT_COMMAND='history -a;history -n'
See more examples and discussions here: http://unix.stackexchange.com/questions/1288/preserve-bash-h...Also I just don't trust bash to actually keep my history, no matter what I do with HISTSIZE and HISTFILESIZE.
I have about a half dozen terminals open. I want to have the current shell's history seem consistent within any shell, but I want ^R in any NEW terminal to include all the commands entered in any terminal.
shopt -s histappend
HISTCONTROL=ignoredups:ignorespace
# append to bash history Right Now
export PROMPT_COMMAND="history -a"
I share your distrust, though -- I've frequently lost my bash history for $REASONS (which another comment here seems to have answered :)) -- but the convenience of not having my shell history clobbered by which-shell-I-close-first is _amazing_.Besides, since you load the HISTFILE at startup, you'll append your whole history (file+session) to the HISTFILE each time you exit a shell, so either it will grow very large quickly, or you set HISTFILESIZE to limit it but as a consequence you'll lose entries (and unfortunately not the oldest).
The option "only append the session entries typed in this session", while still using the whole history (file+session) for searching, is missing, as far as I know.
/down-with-the-kids
$ figlet moo | cowsay -n | cowsay -n
______________________________
/ _________________________ \
| / \ |
| | _ __ ___ ___ ___ | |
| | | '_ ` _ \ / _ \ / _ \ | |
| | | | | | | | (_) | (_) | | |
| | |_| |_| |_|\___/ \___/ | |
| \ / |
| ------------------------- |
| \ ^__^ |
| \ (oo)\_______ |
| (__)\ )\/\ |
| ||----w | |
\ || || /
------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||I've now doubled-down on it and actually store lots of todo notes or receipt numbers or random snippets like that in my shell history as comments. It's just always there :-)
And fortunately btrfs snapshots (and one time, a backup from a laptop migration...) have saved me form losing it for a long time now :-)
Shell history is awesome, I'm always really intrigued when I see someone like a sysadmin who doesn't use shell history very well (read, at all...)
# share history among terminals
setopt share_history
# append to the history instead of overwriting
setopt append_history
# append to history incrementally instead of when the shell exits
setopt inc_append_history
Look ma, no more lost history!https://github.com/barabo/advanced-shell-history
both are fairly featureful and capture additional metadata about the commands run
it is also possible to use similar tools to log your bash history to mysql, or to syslog, which may be preferable for auditing purposes.
I have a function as my prompt command that does:
- dump the current in-memory history into a separate logfile every few minutes timestamped (using HISTTIMEFORMAT)
- clear the local in-memory history and reload in-memory history from unique history lines from all stored log files, using the most recent timestamp on each
Once there are more than N log files, one of the shells does a similar uniquefying compation step for N log files and writes the output into one new log file. It uses 'mv' to do the compation atomically by moving the affected log files away into a temporary directory for compaction.
If other shells were to update their logs during the compaction those additions would just be saved as normal and compacted in the next cycle. There are always duplicate history lines in the logs to keep things fast so there's no chance for a race condition: no command line in the history can get accidentally deleted and any duplicates are just removed during reading.
As a final step I atomically copy the latest compacted history into .bash_history as a backup. The real data lives in my logs anyway but a single .bash_history is easier to backup: it might be a few lines short but it's always mostly up-to-date.
Looking back at this, I reckon the current Bash history implementation surely can't be ideal.
# History stuff.
shopt -s histappend
export HISTFILESIZE=50000
export HISTSIZE=50000
export HISTCONTROL=ignoreboth
export PROMPT_COMMAND='history -a'
Individual shells keep their session history in order, while all commands regardless of which shell triggered them get appended to the history file. # infinite history
HOSTNAME="$(hostname)"
HOSTNAME_SHORT="${HOSTNAME%%.*}"
mkdir -p "${HOME}/.history/$(date -u +%Y/%m/)" > /dev/null 2>&1
SESSIONPREFIX=$(date -u +%Y/%m/%d.%H.%M.%S)
export HISTFILE="${HOME}/.history/${SESSIONPREFIX}_${HOSTNAME_SHORT}_$$"
Only thing you're missing is `HISTFILE`, and an alias like alias histgrep='find ~/.history/ -type f -print0 2>/dev/null | xargs -0 grep --color=auto -InH'
https://news.ycombinator.com/item?id=10162189 for contextSo this does not do anything to manage different sessions clobbering each others' histories. The solution posted by zootboy will work together with this script however.
> hist /youtube-dl
76
youtube-dl --help
> !76:p
brew install soxhttps://stackoverflow.com/questions/43019250/made-quick-scri...
Work for me... I don't lose bash history.
https://github.com/kaihendry/dotfiles/blob/master/.bashrc#L3...
Great idea, thanks for sharing.
Plus a script named "ehist" in my path which contains "cat ~/.bash_eternal_history" -- this enables searches with "ehist | grep git"
It also handles the case of multiple shells writing to a history file.
Naive non-programmers version: use a hash table to censor all substrings of a given length range that match against it ... sounds like it might be expensive (in compute time), also you have to keep a list of those hashes around.
Bet it's been wontfix-ed in at least one major shell?
HISTCONTROL
A colon-separated list of values controlling how commands are
saved on the history list. If the list of values includes
"ignorespace", lines which begin with a space character are not
saved in the history list.
[...]
This is convenient because any time you don't want a command saved in history, just start it with a leading space.Also look at HISTIGNORE for finer grained control.
Next todo was to look if we could send the history to some syslog server - do you have any experiences with a similar solution?
[1] Either inline in mysql-type commands, or when users accidentally paste/type their password in when the system isn't expecting it.
edit: FIRE == OSX specific
Previously, it had to do with my usage of Terminal; I've had to touch ~/.bash_sessions_disable -- /etc/bashrc_Apple_Terminal has the nitty gritty.
Root account never saves history.
Thanks HN!
(o)))><