overthewire bandit walkthrough (computer CTF)

overthewire-bandit walkthrough (computer CTF)

bandit is the simplest levels on overthewire.org and one of the simplest CTF (capture the flag) wargames there is. it uses various bash functions and tricks. several things at first:
- one might find it helpful to specify a bash function that automatically ssh into the various bandit levels like such:
- b () {ssh -p 2220 bandit$1@bandit.labs.overthewire.org} in ~/.bashrc
- don't forget to source ~/.bashrc
- bandit is the first CTF wargame i played. the first time i tried it, i got to around level 15 by myself. i was okay on the git levels and several other levels but i searched for a lot of solutions on the internet. since then i've replayed it a couple of times, but even then i have to go back to notes on a couple levels. so don't be discouraged at this seemingly perfect and compact solution and have fun.
- there are other ways to solve some of these levels, but this walkthrough is already pretty optimal.
- saving passwords (a.k.a. flags) can be a good habit on the first try.
0. ssh
- b 0
- password: bandit0
1. ls, cat
- ls -a to look around in home directory
- cat readme to get password for bandit 1
2. cat special symbol
- a weird file named - that is hard to cat
- but we can always cat ./* to list all the non-hidden files in the current directory
3. same as level 2
4. hidden file
- ~/inhere/.hidden is a hidden file because its name starts with a dot
- to read it, cat ./.*
- this along with cat ./* sweeps all files in a directory
5. use the last three levels to extract this, the password is rather apparent.
- use python -c "print len('koReBOKuIDDepwhWk7jZC0RTdopnAYKh')" to verify the length of the supposed flag
6. find part 1
- this time du ~/inhere tells us that the folder is much larger, around 1.3 megabytes
- follow the requirement and write:
- cat $(find . -readable -size 1033c \! -executable)
- after a bit of trimming the password is apparent again.
7. find part 2
- follow the requirement again
- it'd be useful to redirect all the permission errors to /dev/null
- cat $(find / -size 33c -user bandit7 -group bandit6 2>/dev/null)
8. grep intro
- linux commands can often be combined into moderately powerful scripts
- cat data.txt | grep millionth
9. sort, uniq, tail
- this level is the first complex level that requires some planning
- to play CTF, planning and reconnisance is always better than blind trail and error
- but i suppose a swiss army knife (such as a good injection book) is handy
- follow the specification, we have the following code
- sort data.txt | uniq -c | sort | tail -1
10. strings, head
- this is similar to the last level
- follow the instructions, we have the following code
- strings data.txt | grep === | head -10
11. base64
- base64 -d data.txt
12. rot 13
- there are many ways to solve this level, the best way is to use a library, like Python's Rot13 or CyberChef, i used CyberChef.
13. decompression
- this is the longest level in bandit, if one does not get stuck
- some of the steps can be tricky
- follow manual and error message closely
- complete solution:
- cd $(mktemp -d) makes a temporary directory that has write access
- cp ~/data.txt . so that we can play with it
- xxd -r data.txt a output a reverse hexdump of data.txt with name a
- file a tells us that it is compressed using gzip, was data2.bin
- if we use a or data2.bin as its name and call gunzip, however, an error occurs
- mv a data2.bin;gunzip data2.bin throws an error: unknown suffix
- after some searching online, i found that the extension should be gz
- mv data2.bin data2.gz;gunzip data2.gz fixed the error shown above and peels off the first layer of the flag
- file data2 to see its format, bzip2
- bunzip2 data2 get data2.out
- file data2.out to see it's gzipped data. this time we know what to do
- mv data2.out data2.gz; gunzip data2.gz gives data2
- file data2 to see it's POSIX tar arhicve
- tar -xf data2 to get data5.bin
- file data5.bin to see it's another POSIX tar arhicve
- tar -xf data5.bin to get data6.bin
- file data6.bin to see it's another bzip2 compressed data
- bunzip2 data6.bin to get data6.bin.out
- file data6.bin.out to see it's another POSIX tar arhicve
- tar -xf data6.bin.out to getdata8.bin
- file data8.bin to see it's another gzipped data.
- mv data8.bin data8.gz; gunzip data8.gz gives data8
- file data8 to see it's ASCII text!
- cat data8 to get flag
14. scp, ssh part 2 (part 1 is bandit0)
- another way to authenticate is to use a private key
- first, copy that private key to local machine. in local machine, do:
- scp -P 2220 bandit13@bandit.labs.overthewire.org:~/sshkey.private .
- then, modfy the permission of the key
- chmod 600 ./sshkey.private
- finally, ssh into the next level
- ssh -p 2220 bandit14@bandit.labs.overthewire.org -i ./sshkey.private
15. telnet
- telnet is what was used before browsers are a thing, i suppose
- cat /etc/bandit_pass/bandit14 to get the current level's password
- telnet localhost 30000 to open up a loopback portal
- once the portal opens and system is done printing, paste the result of the cat instruction to the portal to get the password for the next level.
16. openssl s_client
- ssl encrypts the message over the network, supposedly
- very similar to last level
- cat /etc/bandit_pass/bandit15 to get the current level's password
- openssl s_client -connect localhost:30001
- once the portal opens and system is done printing, paste the result of the cat instruction to the portal to get the password for the next level.
17. nmap
- portscan is another important aspect to CTF games
- nmap has scripts to probe other machine's ports
- nmap --script ssl-enum-ciphers -p31000-32000 localhost to find out there are two ports that corresponds to the written requirement: 31518, 31790
- trial and error, and the correct port is 31790:
- cat /etc/bandit_pass/bandit14
- openssl s_client -connect localhost:31790
- submit the current password to the loop to get flag, an RSA key
- just like level 14, submit the rsa key to level 17 to enter as bandit17
- chmod 600 bandit17_rsa where bandit17_rsa is the rsa key
- chmod 600 bandit17_rsa
- ssh -p 2220 bandit17@bandit.labs.overthewire.org -i ./bandit17_rsa
18. diff
- diff ./*
19. ssh part 3
- there are many ways to talk to a remote machine, some of which comes in handy when we are deined permission to log on noramlly. here's one of them that solves this level:
- ssh -p 2220 bandit18@bandit.labs.overthewire.org "cat ~/readme"
20. setuid
- setuid is common in CTF games, as it esscalates priviledge of current user
- usually accompanied with ltrace if we need to hack it but this is the first time so this is easy, as shown below:
- ./bandit20-do cat /etc/bandit_pass/bandit20
21. tmux, nc
- tmux is a good window manager, great tool in general
- nc needs two flags
- the first one is -l, which is reasonable because we want to get the password for the next level.
- the second flag, after some search, is -p. this allows nc to run on local ports.
- this is not usual behavior in modern linux. bandit servers used Deuvan Linux 2.1...
- nc -lp 30002 on one window
- then run the setuid with 30002 on the other window
- read the flag from the window with nc
22. cron part 1: intro to cornjob
- cat /etc/cron.d/cronjob_bandit22 to see that upon reboot and every minute, /usr/bin/cronjob_bandit22.sh is executed
- cat /usr/bin/cronjob_bandit22.sh to see that the flag is in /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv with appropriate read permissions (4 for group)
- permission is very important in a later level, bandit24.
- cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv to get flag
23. cron part 2: reverse engineering
- reverse engineering is a great way to think about a lot of problems. reversing is an important spirit of hacking and creative problem solving in general.
- '[a general who] knows his own army as well as the enemie's will not lose in a hundred wars.' ---- the art of war
- cat /etc/cron.d/cronjob_bandit23 to see that upon reboot and every minute, /usr/bin/cronjob_bandit23.sh is executed
- cat /usr/bin/cronjob_bandit23.sh to see that the level is more complex than the last one. basically it use some rules to write its password in a readable file. but the file's parent directory, tmp, is itself unreadable. we need to reverse the filename.
- export myname=bandit23 because we want to impersonate bandit23 to get his pasword
- then we want to do basically the same thing as the bash code to get flag:
- > cat /tmp/$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
24. cron part 3: file inclusion
- for every minute, the bash code /usr/bin/cronjob_bandit24.sh checks /var/spool/bandit24 and tries to execute each file in there for sixty seconds, then it wipes everything in that folder.
- if one merely writes cp /etc/bandit_pass/bandit24 /tmp/somefile and include it in /var/spool/bandit24, nothing will happen. this is because bandit24 lacks permission to execute it.
- one also needs to set group write permission for target folder so that bandit24 can write.
- this is another case of walking in other's shoes
- lastly, one needs to write chmod 777 /tmp/some_tmp_dir/somefile so we can read it
- so chmod 777 /tmp/some_tmp_dir/get_24.sh and chmod 777 /tmp/some_tmp_dir before the inclusion
- cp /tmp/some_tmp_dir/get_24.sh /var/spool/bandit24 , wait a minute, and cat /tmp/somefile
- thinking through and constructing a series of gadgets to achieve something is common in CTF games, such as making an exploit sandwitch.
25. nc part 2: brute force
- create and run the following bash script:
- for i in {0000..9999} do echo UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ $i >> attempts.txt done
- then cat attempts.txt | nc localhost 30002
26. find, grep, more, vim
- finding things is a great skill in hacking and in life in general. if we can't find matching folder (first try), we try to find matching content (second try).
- however, matching content can be very slow on a spinning disk with a large file tree (see broot's running speed on an old drive when fed in something like c/xyz).
- first try: find / -iname "\*bandit26\*" 2>/dev/null, no good.
- second try: grep -rnw / -e bandit26 2>/dev/null, lead us to /usr/bin/showtext
- showtext tells us that TERM is messed up, and the connection gives a more program
- the character of more is that it becomes more flexible when the window is smaller than all the texts it's trying to show.
- resize the window so that the height is smaller than that of 'bandit26' and press v to trigger vim
- once in vim, do each of these instruction following a colon:
- set shell=/bin/bash
- !./bandit27-do cat /etc/bandit_pass/bandit27
27. git part 1: clone
- saving passwords can be helpful for the git levels.
- this level is simple
- cd $(mktemp -d)
- git clone ssh://bandit27-git@localhost/home/bandit27-git/repo
- cat ./repo/*
28. git part 2: log, checkout
- password in an earlier commit
- cd repo; git checkout HEAD~1
- cat ./*
29. git part 3: branch
- no password in production says local repo
- so password is in development
- git branch --remote to see dev branch
- git checkout -b origin/dev
- cat ./*
30. git part 4: tag
- this is one of the harder levels. after some reading one can see there's another piece of information, the tag.
- git tag gives us secret
- git show secret
- (in practice, add tag from github's GUI...)
31. git part 5: push, gitignore
- this has more practical value compared to the last level.
- if one naively push the repo, one would get everything up to date and nothing else.
- echo 'May I come in?' >> key.txt
- git add -A; git commit -m "solve"; git push origin master
- but if one reads the messages from git, ti's not hard to figure out waht's wrong
- firstly, git add has no reaction. this is abnormal. we just created a file and wrote some things to it!
- secondly, git commit says nothing to commit, but again there is one more file this time
- this leads to a look at .gitignore
- cat ./.* gives us *.txt
- git ignores all txt files.
- so remove .gitignore and try again
32. 'uppercase shell' (ad hoc)
- this is one of the harder levels and it's also interesting.
- if one tries the same trick as level 26, there's no luck.
- du uppershell gives a scary 8 kb file size. (which means it's at least 4 kb)
- first observation: numbers are echoed with not found, letters are capitalized with not found
- second observation: special symbols generally trigger special responses
- third observaton: . triggers no response
- fourth observation: ./* triggers welcome response, WELCOME TO UPPERCASE SHELL
- fifth observation: ../* gives us ../bandit0: permission deined
- sixth observation: ../../* gives us ../../: permission deined
- best guess at this point: this code rests in bandit32's home directory, capitalizes all letters and tries to run the result
- so to make progress, we cannot use any letters. that means we cannot go to the password file directly
- we have to get shell without explicitly writing /bin/bash
- this suggests $0, the first variable is always the current shell
- then simply cat /etc/bandit_pass/bandit33 to finish the last level.

React .Net Core 3 Search Bar - lessons learned

link to proj
Finding a search bar in react is easy. Finding a .net project is easy too. The interesting part about this project is bridging these two technologies together. There are less materials out there about the intersection of two technologies, oftentimes. When one asks on Discord about a specific language (that is, under the right server & channel), it's usually pretty easy to get a solid response. In this case, however, it's harder. Folks would flat out tell ya they don't know either. But if you keep digging and thinking about different solutions, you get more familiar with the tech stack and find others' advises useful in the end.



0 - ssh, cat
pretty standard ssh:
ssh -p 2220 bandit0@bandit.labs.overthewire.org
the password is on desktop/readme:
cat readme
1 - better cat
this level introduces a standard theme to all bandit levels: if it doesn't
work, tweak it until it does:
cat ./-
2 - even better cat
modern linux systems auto-completes the escape character (\) for spaces in
file name, making this level easy:
cat spaces\ in\ this\ filename
3 - hidden file
an easy google lookup should tell ya that a hidden file starts with a
bandit3@bandit:~$ ls inhere/ -a
.  ..  .hidden
bandit3@bandit:~$ cat inhere/.hidden 
4 - file type
this is when we need to start to rtfm:
bandit4@bandit:~$ file inhere/*
inhere/-file00: data
inhere/-file01: data
inhere/-file02: data
inhere/-file03: data
inhere/-file04: data
inhere/-file05: data
inhere/-file06: data
inhere/-file07: ASCII text
inhere/-file08: data
inhere/-file09: data
bandit4@bandit:~$ cat inhere/-file07
5 - much better find
there are lots of tricks to an instruction like find, here's my
find inhere/*/.* -size 1033c \! -executable -readable \! -path "*/../*" \!
-path "*/./*"
6 - find then cat
there's a neat one-liner for this:
cat $(find / -user bandit7 -group bandit6 -size 33c 2>/dev/null)
7 - grep
pretty standard:
bandit7@bandit:~$ ls
bandit7@bandit:~$ man grep
bandit7@bandit:~$ grep millionth data.txt 
millionth       cvX2JJa4CFALtqS87jk27qwqGhBM9plV
8 - sort, uniq, grep, pipe
after some trial and errors, I realized that uniq only works with sort.
another thing to notice is grep can find the line with frequency 1 after
uniq. pipe, the most powerful tool in bash is introduced:
bandit8@bandit:~$ sort data.txt | uniq -c | grep '1 '
1 UsvVyFSfZZWbi6wgC7dAFyFuR6jQQUhR
9 - strings, grep, pipe
pretty standard after level 8:
bandit9@bandit:~$ man strings
bandit9@bandit:~$ strings data.txt | grep ===
2========== the
========== password
========== isa
========== truKLdjsbJ5g7yyJ2X2R0o3a5HQJFuLk
10 - base64
base64 is an encoding for files, and base64 command in bash can help
encoding/decoding with the format:
bandit10@bandit:~$ man base64
bandit10@bandit:~$ du data.txt 
4       data.txt
bandit10@bandit:~$ base64 -d data.txt 
The password is IFukwKGsFW8MOq3IRFqrxE1hxTNEbUPR
11 - rot13
i used python for this one:
bandit11@bandit:~$ chmod 775 /tmp/mikey2521/rot13.py
bandit11@bandit:~$ python3 /tmp/mikey2521/rot13.py < data.txt 
The password is 5Te8Y4drgCRfCx8ugdwuEX8KFC6k2EUu
bandit11@bandit:~$ cat /tmp/mikey2521/rot13.py
for c in cipher:
if c.islower():
elif c.isupper():
12 - file, various compression commands
first move data.txt to your directory in /tmp/:
mkdir /tmp/your-dir
mv data.txt /tmp/your-dir
then go to your directory and revert the hexdump:
cd /tmp/your-dir
xxd -r data.txt > reverted
upon using file on reverted, we find that it's a gzip compressed file named
bandit12@bandit:/tmp/mikey2521/lvl12$ file reverted 
reverted: gzip compressed data, was "data2.bin", last modified: Tue Oct 16
12:00:23 2018, max compression, from Unix
if only gunzip is used, even with the original name of data.bin, the
following error occurs:
bandit12@bandit:/tmp/mikey2521/lvl12$ gunzip reverted
gzip: reverted: unknown suffix -- ignored
after some search online, i realized that a .Z suffix is needed:
mv reverted reverted.Z
gunzip reverted.Z
this time the compression seems to be bzip2:
bandit12@bandit:/tmp/mikey2521/lvl12$ file reverted 
reverted: bzip2 compressed data, block size = 900k
and it went nicely, giving another gzipped file:
bandit12@bandit:/tmp/mikey2521/lvl12$ bunzip2 reverted
bunzip2: Can't guess original name for reverted -- using reverted.out
bandit12@bandit:/tmp/mikey2521/lvl12$ file reverted.out 
reverted.out: gzip compressed data, was "data4.bin", last modified: Tue Oct
16 12:00:23 2018, max compression, from Unix
trying naive gunzip yields the same error before, so change the suffix to .Z
one more time and decompress:
bandit12@bandit:/tmp/mikey2521/lvl12$ mv reverted.out reverted.Z
bandit12@bandit:/tmp/mikey2521/lvl12$ gunzip reverted.Z
then use tar to decompress:
tar xf reverted
upon yielding data5.bin and finding it a tar archive again, produce
tar xf data5.bin
data6.bin is another bzipped file, so use bunzip:
bunzip data6.bin
data6.bin.out is another tar archive which produces data8.bin, a gzipped
tar xf data6.bin.out
mv data8.bin data8.Z
gunzip data8.Z
this finally gives the password file, data8:
bandit12@bandit:/tmp/mikey2521/lvl12$ file data8
data8: ASCII text
bandit12@bandit:/tmp/mikey2521/lvl12$ cat data8
The password is 8ZjyCRiBWFYkneahHwxCv3wb2a1ORpYL
14 - sshkey
copy the sshkey to a local file of random name 
don't forget to change permission of the file to 700
use -i flag in ssh to remote into level 14:
chmod 700 lvl14key
ssh -p 2220 bandit14@bandit.labs.overthewire.org -i lvl14key 
15 - nc
pretty straightforward if you know where bandit14's password is:
cat /etc/bandit_pass/bandit14 | nc localhost 30000
16 - yet another port scan
first, use nmap to detect open ports:
nmap localhost -p 31000-32000
then, use openssl and s_client to talk to the server. after a failure, the
server on port 31790 returns a RSA key. use that key to connect to the next
level (just like an earlier level):
openssl s_client -connect localhost:31790
ssh -p 2220 bandit17@bandit.labs.overthewire.org -i lvl17key
17 - diff
standard solution:
diff passwords.old passwords.new
i prefer vimdiff
vimdiff passwords.old passwords.new
18 - malicious bashrc, command over ssh
after a little trial and error, here's the solution:
ssh -p 2220 bandit18@bandit.labs.overthewire.org "cat ~/readme"
19 - setuid binary, priviledge escalation
the instruction is not so clear for this one and it took some unnecessary
time for me to guess the straightforward solution:
./bandit20-do cat /etc/bandit_pass/bandit20
20 - netcat, tcp
the description took me quite a while to figure out what to do. but basically
you first open one window and write:
nc -lp 31791 < /etc/bandit_pass/bandit20
then another window and write:
./suconnect 31791
the logic is that the a port on the localhost (default for nc) will have the
old password on it. when suconnect reaches it, suconnect sends the new
password into the port and the -l flag ensures we get the password.
21 - cron
cron runs scheduled tasks
bandit22's cronjob is a shell script that enables me to read its password,
its time is set to every minute, so i can just read the password:
cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
22 - more cron, bash
this takes some reverse engineering. the password is hidden inside tmp
folder, which i cannot read. however, i can read all files' content in /tmp.
the password is hidden because it uses a processed md5sum based on the
username. but this is deterministic so it's easy to reconstruct.
cat /tmp/$mytarget
where mytarget is:
echo I am user bandit23 | md5sum | cut -d ' ' -f 1
23 - bash, simple exploit
the thought is along the lines of level 22. you need to identify a weakness
in the victim script and use it to your advantage. it is more straightforward
in a way once you understand what the bash script is doing. the script is
simply executing and removing all the files in /var/spoof/bandit24. so just
sneak a file in there that leaks the password. notice the password needs to
be written to a place that has write permission and the file needs to have
execute permission:
mkdir /tmp/oh_long_johnson
chmod 777 /tmp/oh_long_johnson 
vim /var/spoof/bandit24/leak24.sh
(inside vim)
cat /etc/bandit_pass/bandit24 >> /tmp/oh_long_johnson/b24.txt
(outside vim)
chmod 777 /var/spoof/bandit24/leak24.sh
#wait a minute
cat /tmp/oh_long_johnson/b24.txt
24 - bash, burte force
this one i actually used python3. since it's slower than bash, i need to cut
the guess in half (0-5,000, 5,000-10,000) and here's the code (named
pswd='UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ '
with open('out.txt','w') as f:
for i in range(5000,10000):
use this to produce a list of guesses and use an earlier level to get the
uniqe lines that contains the password (since thankfully all the error
messages are the same):
python3 b25.py
nc localhost 30002 < out.txt > out2.txt
sort out2.txt | uniq -c | grep '1 '    
25 & 26 - more, set shell
these two levels are pretty hard. i did not do this on my own.
first, we need to notice in level 25 what level 26 is doing:
cat /etc/passwd | grep bandit26
this is a common exploit for earlier linux/unix systems, but it's hard for
newcomers to learn about this at first. however, once this is done, one can
follow a thread of information until one gets the private ssh key for level
26, as well as knowing what level 26 is doing: 
1. switching terminal emulator to linux    
2. call more on text.txt
3. exit
hmm... it seems a terminal emulator is pretty unhackable at the moment, when
we can't influence it by any commands in ssh. the exit throws us right back
to our local machine. the only point of weakness left is the 'opposite of
less', more. more is only triggered when there's more to the document than
the screen. so with a six line document, i had to squash the terminal window
to less than six lines tall... but even then i can't do much within more.
it's not like vim, where there's a million things i can do to hack the
'outside world'.
it's time to rtfm.
after a rather painful search in more's man page, a command finally brings a
hope: v. v calls the text editor that starts with v, vim, and opens a path to
once vim is opened, there are usually many ways to call external shell
commands and do almost everything in vim. but in this case i could only set
the shell by, well, 'set shell=/bin/bash'. then it's just a priviledge
escalation (setuid) and we're onto a couple of easy levels using git.
27 - git clone
just clone it and cat the readme file.
28 - git log, checkout
the cloned repo has no real password. so a natural thing to think about is
log and previous versions. from log's comments i was able to recover the
password from a previous commit. pretty standard.
29 - git branch
first use:
git show-branch -a
git checkout origin/dev
cat README.md
30 - git show    
git clone...
git tag
git show secret
31 - git add, git commit, git push
pretty standard
32 - redirection
>> is probably redirecting, and converts everything to uppercase in the
the correct command is $0 to get it redirected to bash

First Previous 1 2 3 4 5 Next Last