Impossible Conditions
Writeup by hgarrereyn
- Reverse Engineering
- 30 points
- Let’s make the impossible possible! Let’s make 1=5. impossible.out
Solution
Running this binary produces no output and exits immediately. Let's take a look at the disassembly.
First we notice a bunch of suspicious mov
operations that appear to be swapping some char codes around.
Then we see some get_time
methods right before a je
(line 0x401420
) that skips a large chunk of code:
main:
0000000000400e06 push rbp ; DATA XREF=_start+29
0000000000400e07 mov rbp, rsp
0000000000400e0a push r15
0000000000400e0c push r14
0000000000400e0e push r13
0000000000400e10 push r12
0000000000400e12 push rbx
0000000000400e13 sub rsp, 0x1e8
0000000000400e1a mov rax, qword [fs:0x28]
0000000000400e23 mov qword [rbp+var_38], rax
0000000000400e27 xor eax, eax
0000000000400e29 mov byte [m], 0x6d
0000000000400e30 mov byte [n], 0x6e
0000000000400e37 mov byte [z], 0x7a
<many lines omitted>
0000000000401362 mov byte [z], 0x21
0000000000401369 mov byte [n], 0x6e
0000000000401370 mov byte [x], 0x78
0000000000401377 lea rax, qword [rbp+var_1F0]
000000000040137e mov esi, 0x0 ; argument "tzp" for method j_gettimeofday
0000000000401383 mov rdi, rax ; argument "tp" for method j_gettimeofday
0000000000401386 call j_gettimeofday
000000000040138b mov rax, qword [rbp+var_1F0]
0000000000401392 mov qword [rbp+var_1F8], rax
0000000000401399 lea rax, qword [rbp+var_1F8]
00000000004013a0 mov rdi, rax ; argument "clock" for method j_localtime
00000000004013a3 call j_localtime
00000000004013a8 mov rdx, rax
00000000004013ab lea rax, qword [rbp+var_60]
00000000004013af mov rcx, rdx ; argument "timeptr" for method j_strftime
00000000004013b2 mov edx, 0x401a54 ; "%m-%d-%Y\\t%T.", argument "format" for method j_strftime
00000000004013b7 mov esi, 0x1e ; argument "maxsize" for method j_strftime
00000000004013bc mov rdi, rax ; argument "s" for method j_strftime
00000000004013bf call j_strftime
00000000004013c4 lea rax, qword [rbp+var_1FE]
00000000004013cb mov rdi, rax
00000000004013ce call j__ZNSaIcEC1Ev
00000000004013d3 lea rdx, qword [rbp+var_1FE]
00000000004013da lea rcx, qword [rbp+var_60]
00000000004013de lea rax, qword [rbp+var_80]
00000000004013e2 mov rsi, rcx
00000000004013e5 mov rdi, rax
00000000004013e8 call j__ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_
00000000004013ed lea rax, qword [rbp+var_80]
00000000004013f1 mov esi, 0x401a61
00000000004013f6 mov rdi, rax
00000000004013f9 call j__ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc
00000000004013fe test eax, eax
0000000000401400 sete bl
0000000000401403 lea rax, qword [rbp+var_80]
0000000000401407 mov rdi, rax
000000000040140a call j__ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev
000000000040140f lea rax, qword [rbp+var_1FE]
0000000000401416 mov rdi, rax
0000000000401419 call j__ZNSaIcED1Ev
000000000040141e test bl, bl
0000000000401420 je loc_4017be
0000000000401426 lea rax, qword [rbp+var_1FE]
000000000040142d mov rdi, rax
0000000000401430 call j__ZNSaIcEC1Ev
...
Using gdb we can break at the jump and see if we take it:
$ gdb -q impossible
Reading symbols from impossible...(no debugging symbols found)...done.
(gdb) b *0x401420
Breakpoint 1 at 0x401420
(gdb) r
Starting program: /home/ubuntu/pactf/impossible
Breakpoint 1, 0x0000000000401420 in main ()
(gdb) ni
0x00000000004017be in main ()
Notice that the instruction pointer did indeed jump to 0x4017be
.
Now, let's use gdb to skip over that je
and continue execution right after it.
Note: be sure to set $rip
not $eip
since this is a 64 bit binary
$ gdb -q impossible
Reading symbols from impossible...(no debugging symbols found)...done.
(gdb) b *0x401420
Breakpoint 1 at 0x401420
(gdb) r
Starting program: /home/ubuntu/pactf/impossible
Breakpoint 1, 0x0000000000401420 in main ()
(gdb) set $rip=0x401426
(gdb) c
Continuing.
abcx!ilgdn
[Inferior 1 (process 1329) exited normally]
Oh look! It printed out something before exiting this time.
That's our flag!
Flag: abcx!ilgdn