Binary Fun: With basic binary file analysis
A little bit ago I decided CTFs looked like alot of fun and that I want to get involved. At least for me it was a little daunting picking where to start. Some people would start with things they are familiar with but I thought Reverse Engineering sounded cool so I went with that. I got a small binary made by a friend, intended to be similar to a basic reversing challenge, to start with.
The file is titled pwd2 and we can run a couple of quick bash commands to see if we can find any useful information. I went ahead and spun up a fresh Ubuntu VM for obvious reasons. Of course lets run it first and see what it wants.
user@ubuntu:~$./pwd2 Please supply 3 digit passcode 222 Nope
The next thing to do would be to run the file command and see if we can grab any other basic information.
user@ubuntu:~$file pwd2 ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID<br /> [sha1]=82ef1e7313ec65f084871b449de99df70ba27282, stripped
Alright so it is pretty apparent what it wants. At the time I first received this I didnt know about String Format vulns otherwise I wouldve tried seeing if I couldve gained the password value that way. Additionally I didnt think to try integer underflow or overflow, but I did try a simple buffer overflow and can say that did not work.
At least now Ive got some more ideas of things to look for. The one useful thing I did get from that file command was that debug symbols are stripped.
Despite seeing that the binary is stripped, I am still going to try gdb on it. Ive used it before with varying degrees of success and still want to become better with it.
user@ubuntu:~$ gdb ./pwd2 (gdb) r Starting program: /home/user/ex1/pwd2 denied. [Inferior 1 (process 7311) exited with code 01] (gdb)
Having seemingly hit a wall here, I put a good bit of googling to work. Most on obfuscation of C binaries and things that would try to prevent debuggers. Fortunately I found an article on Securing iOS apps that mentioned a bit about how one may prevent a debugger using dlsym. Dlsym would be dynamically opening a library and calling some sort of function to prevent our debugger. Ubuntu has a nifty tool called ltrace, or library trace, that will call the program and run it until exit. All the while recording all of the dynamic library calls.
user@ubuntu:~$ ltrace ./pwd2 __libc_start_main(0x4007ed, 1, 0x7fff898547b8, 0x400850 <unfinished ...> dlopen(nil, 258) = 0x7f32fd4971c8 dlsym(0x7f32fd4971c8, "ptrace") = 0x7f32fcd9c4f0 puts("denied.\n"denied.
So there we have it, ptrace is preventing our debugger. Which is neat new knowledge but Im going to exhaust all other low hanging fruit before I begin to look into what more I can do with that.
Lets run strings, because sometimes, it really does work.
user@ubuntu:~$ strings ./pwd2 /lib64/ld-linux-x86-64.so.2 libdl.so.2 _ITM_deregisterTMCloneTable __gmon_start__ _Jv_RegisterClasses _ITM_registerTMCloneTable dlclose dlsym dlopen libc.so.6 exit __isoc99_scanf puts __libc_start_main GLIBC_2.2.5 GLIBC_2.7 UH-h UH-h =1 A\A]A^A_ ptrace denied. Please supply 3 digit passcode Nope Win. ;*3$
It was unlikely that an int would be stored as a string but it only takes quick moment to verify.
A big part of learning reverse engineering has been attemping to become comfortable with assembly. I did have to learn and even write some in college so I have a slight heading on where to start. I figure we can objdump the binary to a file and grep through the assembly looking for a cmp instruction. Looking at the cmp instruction and the surrodning instructions could give away the spot where the conditional is checking for the passcode. Of course since the binary is stripped, it is going to be quite the ridiculous garbled output.
520 4007ed: 55 push %rbp 521 4007ee: 48 89 e5 mov %rsp,%rbp 522 4007f1: 48 83 ec 20 sub $0x20,%rsp 523 4007f5: 89 7d ec mov %edi,-0x14(%rbp) 524 4007f8: b8 00 00 00 00 mov $0x0,%eax 525 4007fd: e8 7b ff ff ff callq 40077d <dlsym@plt+0xfd> 526 400802: bf e8 08 40 00 mov $0x4008e8,%edi 527 400807: e8 04 fe ff ff callq 400610 <puts@plt> 528 40080c: 48 8d 45 fc lea -0x4(%rbp),%rax 529 400810: 48 89 c6 mov %rax,%rsi 530 400813: bf 07 09 40 00 mov $0x400907,%edi 531 400818: b8 00 00 00 00 mov $0x0,%eax 532 40081d: e8 3e fe ff ff callq 400660 <__isoc99_scanf@plt> 533 400822: 8b 45 fc mov -0x4(%rbp),%eax 534 400825: 3d 8f 01 00 00 cmp $0x18f,%eax 535 40082a: 74 11 je 40083d <dlsym@plt+0x1bd> 536 40082c: bf 0a 09 40 00 mov $0x40090a,%edi 537 400831: e8 da fd ff ff callq 400610 <puts@plt> 538 400836: b8 00 00 00 00 mov $0x0,%eax 539 40083b: eb 0f jmp 40084c <dlsym@plt+0x1cc> 540 40083d: bf 0f 09 40 00 mov $0x40090f,%edi 541 400842: e8 c9 fd ff ff callq 400610 <puts@plt> 542 400847: b8 00 00 00 00 mov $0x0,%eax</
The assembly code was quite massive with over 1033 lines but I managed to ferret out the above block as one warranting closer examination. Simply because puts and scanf caught my eye. Looking two below the scanf(532) we have cmp at 534. The first value 0x18f is compared against whatever is at %eax. 533 is a mov that takes our value and pushes it to %eax so we can conclude our value at %eax is compared against 0x18f. A quick hex to base 10 conversion reveals 0x18f to be 399. Lets give it a try.
user@ubuntu:~$ ./pwd2 Please supply 3 digit passcode 399 Win.
It worked but Im quite fortunate in the fact that puts and scanf werent also put under dlsym as that wouldve made it a good bit harder to identify. Additionally Im fortunate in that the passcode was stored simply and not obfuscated any further. It was a fun challenge and Im looking forward to doing more of these