ETA?
Writeup by hgarrereyn
- Reverse Engineering
- 60 points
- Description: If this script were to finish, what would it output? MacOS Linux
Solution
After running the script and watching the prompt hang for 30 seconds, it is pretty clear that the script would either hang forever or take an inordinate amount of time to finish. Rather than solve the halting problem, I opted to do some dynamic analysis.
I viewed the disassembly in Hopper and tried to find the part of the code that was causing the program to hang.
Early on in main
, I found the following function call:
0000000000400dac lea rax, qword [rbp+var_40]
0000000000400db0 mov esi, 0x7ffffffc
0000000000400db5 mov rdi, rax ; argument #1 for method _Z10get_primesm
0000000000400db8 call _Z10get_primesm
Hmm, maybe this could be the problem. Let's find out. I'll set a breakpoint after the function call and see if we hit it.
$ gdb -q eta
Reading symbols from eta...(no debugging symbols found)...done.
(gdb) b *0x400dbd
Breakpoint 1 at 0x400dbd
(gdb) r
Starting program: /home/ubuntu/pactf/eta
Breakpoint 1, 0x0000000000400dbd in main ()
We hit the breakpoint after about a minute so this isn't the problem.
Side note: I actually found this out on accident by running the program assuming it would hang on the get_primes
function. I switched windows and started googling something and when I switched back in a few minutes, it had reached the breakpoint.
Next we see some sort of loop followed by an ostream
call to print something to the console.
0000000000400ddc mov qword [rbp+var_70], 0x0
0000000000400de4 mov dword [rbp+var_14], 0x0
0000000000400deb mov dword [rbp+var_18], 0x0
loc_400df2:
0000000000400df2 cmp dword [rbp+var_18], 0xf423f ; CODE XREF=main+196
0000000000400df9 jg loc_400e5d
0000000000400dfb lea rax, qword [rbp+var_60]
0000000000400dff mov rdi, rax
0000000000400e02 call _ZNSt6vectorImSaImEE5beginEv ; std::vector<unsigned long, std::allocator<unsigned long> >::begin()
0000000000400e07 mov qword [rbp+var_70], rax
loc_400e0b:
0000000000400e0b lea rax, qword [rbp+var_60] ; CODE XREF=main+190
0000000000400e0f mov rdi, rax
0000000000400e12 call _ZNSt6vectorImSaImEE3endEv ; std::vector<unsigned long, std::allocator<unsigned long> >::end()
0000000000400e17 mov qword [rbp+var_20], rax
0000000000400e1b lea rdx, qword [rbp+var_20]
0000000000400e1f lea rax, qword [rbp+var_70]
0000000000400e23 mov rsi, rdx ; argument #2 for method _ZN9__gnu_cxxltIPmSt6vectorImSaImEEEEbRKNS_17__normal_iteratorIT_T0_EESA_
0000000000400e26 mov rdi, rax ; argument #1 for method _ZN9__gnu_cxxltIPmSt6vectorImSaImEEEEbRKNS_17__normal_iteratorIT_T0_EESA_
0000000000400e29 call _ZN9__gnu_cxxltIPmSt6vectorImSaImEEEEbRKNS_17__normal_iteratorIT_T0_EESA_ ; bool __gnu_cxx::operator< <unsigned long*, std::vector<unsigned long, std::allocator<unsigned long> > >(__gnu_cxx::__normal_iterator<unsigned long*, std::vector<unsigned long, std::allocator<unsigned long> > > const&, __gnu_cxx::__normal_iterator<unsigned long*, std::vector<unsigned long, std::allocator<unsigned long> > > const&)
0000000000400e2e test al, al
0000000000400e30 je loc_400e57
0000000000400e32 lea rax, qword [rbp+var_70]
0000000000400e36 mov rdi, rax
0000000000400e39 call _ZNK9__gnu_cxx17__normal_iteratorIPmSt6vectorImSaImEEEdeEv ; __gnu_cxx::__normal_iterator<unsigned long*, std::vector<unsigned long, std::allocator<unsigned long> > >::operator*() const
0000000000400e3e mov rax, qword [rax]
0000000000400e41 mov dword [rbp+var_14], eax
0000000000400e44 lea rax, qword [rbp+var_70]
0000000000400e48 mov esi, 0x0
0000000000400e4d mov rdi, rax ; argument #1 for method _ZN9__gnu_cxx17__normal_iteratorIPmSt6vectorImSaImEEEppEi
0000000000400e50 call _ZN9__gnu_cxx17__normal_iteratorIPmSt6vectorImSaImEEEppEi ; __gnu_cxx::__normal_iterator<unsigned long*, std::vector<unsigned long, std::allocator<unsigned long> > >::operator++(int)
0000000000400e55 jmp loc_400e0b
loc_400e57:
0000000000400e57 add dword [rbp+var_18], 0x1 ; CODE XREF=main+153
0000000000400e5b jmp loc_400df2
The loop counter (var_18
) is initialized to zero and incremented each loop. The loop will terminate once it reaches 0xf423f
or 999999
. We also see a bunch of vector initializations going on in the loop. So this must be where we are hanging.
The print is performed by the following (outside of the loop):
loc_400e5d:
0000000000400e5d mov eax, dword [rbp+var_14] ; CODE XREF=main+98
0000000000400e60 mov esi, eax
0000000000400e62 mov edi, 0x602ea0
0000000000400e67 call j__ZNSolsEi
0000000000400e6c mov esi, 0x400b00
0000000000400e71 mov rdi, rax
0000000000400e74 call j__ZNSolsEPFRSoS_E
So we see that var_14
gets printed ($rbp-20
). Also, we notice that the same variable is written to inside the loop. Let's examine a few iterations to see if we can find out what it is set to.
$ gdb -q eta
Reading symbols from eta...(no debugging symbols found)...done.
(gdb) b *0x400df2
Breakpoint 1 at 0x400df2
(gdb) define hook-stop
Type commands for definition of "hook-stop".
End with a line saying just "end".
>x/x $rbp-20
>end
(gdb) r
Starting program: /home/ubuntu/pactf/eta
0x7fffffffe51c: 0x00000000
Breakpoint 1, 0x0000000000400df2 in main ()
(gdb) c
Continuing.
0x7fffffffe51c: 0x7fffffed
Breakpoint 1, 0x0000000000400df2 in main ()
(gdb) c
Continuing.
0x7fffffffe51c: 0x7fffffed
Breakpoint 1, 0x0000000000400df2 in main ()
(gdb) c
Continuing.
0x7fffffffe51c: 0x7fffffed
Breakpoint 1, 0x0000000000400df2 in main ()
Hmm, it doesn't seem to change. Every loop, it is set to 0x7fffffed
or 2147483629
.
So the flag must be 2147483629
.