Can you get the flag? Reverse engineer this binary.
The challenge strongly hints (it's in the binary name, challenge name, and is a literal hint) that this is a binary packed with UPX. Additionally, running strings unpackme-upx | grep upx
displays Info: This file is packed with the UPX executable packer http://upx.sf.net $
. According to their website, "UPX is a free, portable, extendable, high-performance executable packer for several executable formats."
We can download the latest release of UPX from the GitHub releases page. Extracting the archive gives us a folder with a upx
binary. We can run ./upx -d unpackme-upx
to decompress the binary and replace it on disk. Now, our unpackme-upx
file is unpacked.
Next, run gdb ./unpackme-upx
and layout asm
(or disassemble main
) to get:
0x0000000000401e73 <+0>: endbr64
0x0000000000401e77 <+4>: push %rbp
0x0000000000401e78 <+5>: mov %rsp,%rbp
0x0000000000401e7b <+8>: sub $0x50,%rsp
0x0000000000401e7f <+12>: mov %edi,-0x44(%rbp)
0x0000000000401e82 <+15>: mov %rsi,-0x50(%rbp)
0x0000000000401e86 <+19>: mov %fs:0x28,%rax
0x0000000000401e8f <+28>: mov %rax,-0x8(%rbp)
0x0000000000401e93 <+32>: xor %eax,%eax
0x0000000000401e95 <+34>: movabs $0x4c75257240343a41,%rax
0x0000000000401e9f <+44>: movabs $0x30623e306b6d4146,%rdx
0x0000000000401ea9 <+54>: mov %rax,-0x30(%rbp)
0x0000000000401ead <+58>: mov %rdx,-0x28(%rbp)
0x0000000000401eb1 <+62>: movabs $0x3532666630486637,%rax
0x0000000000401ebb <+72>: mov %rax,-0x20(%rbp)
0x0000000000401ebf <+76>: movl $0x36665f60,-0x18(%rbp)
0x0000000000401ec6 <+83>: movw $0x4e,-0x14(%rbp)
0x0000000000401ecc <+89>: lea 0xb1131(%rip),%rdi # 0x4b3004
0x0000000000401ed3 <+96>: mov $0x0,%eax
0x0000000000401ed8 <+101>: call 0x410df0 <printf>
0x0000000000401edd <+106>: lea -0x3c(%rbp),%rax
0x0000000000401ee1 <+110>: mov %rax,%rsi
0x0000000000401ee4 <+113>: lea 0xb1135(%rip),%rdi # 0x4b3020
0x0000000000401eeb <+120>: mov $0x0,%eax
0x0000000000401ef0 <+125>: call 0x410f80 <__isoc99_scanf>
0x0000000000401ef5 <+130>: mov -0x3c(%rbp),%eax
0x0000000000401ef8 <+133>: cmp $0xb83cb,%eax
0x0000000000401efd <+138>: jne 0x401f42 <main+207>
0x0000000000401eff <+140>: lea -0x30(%rbp),%rax
0x0000000000401f03 <+144>: mov %rax,%rsi
0x0000000000401f06 <+147>: mov $0x0,%edi
0x0000000000401f0b <+152>: call 0x401db5 <rotate_encrypt>
0x0000000000401f10 <+157>: mov %rax,-0x38(%rbp)
0x0000000000401f14 <+161>: mov 0xdd7b5(%rip),%rdx # 0x4df6d0 <stdout>
0x0000000000401f1b <+168>: mov -0x38(%rbp),%rax
0x0000000000401f1f <+172>: mov %rdx,%rsi
0x0000000000401f22 <+175>: mov %rax,%rdi
0x0000000000401f25 <+178>: call 0x420bd0 <fputs>
0x0000000000401f2a <+183>: mov $0xa,%edi
0x0000000000401f2f <+188>: call 0x421070 <putchar>
0x0000000000401f34 <+193>: mov -0x38(%rbp),%rax
0x0000000000401f38 <+197>: mov %rax,%rdi
0x0000000000401f3b <+200>: call 0x42eec0 <free>
0x0000000000401f40 <+205>: jmp 0x401f4e <main+219>
0x0000000000401f42 <+207>: lea 0xb10da(%rip),%rdi # 0x4b3023
0x0000000000401f49 <+214>: call 0x420e90 <puts>
0x0000000000401f4e <+219>: mov $0x0,%eax
0x0000000000401f53 <+224>: mov -0x8(%rbp),%rcx
0x0000000000401f57 <+228>: xor %fs:0x28,%rcx
0x0000000000401f60 <+237>: je 0x401f67 <main+244>
0x0000000000401f62 <+239>: call 0x45cdf0 <__stack_chk_fail_local>
0x0000000000401f67 <+244>: leave
0x0000000000401f68 <+245>: ret
We know that the program asks for a number and then will probably print the flag given the correct number. So, we are looking for a cmp
instruction. We see <+133>: cmp $0xb83cb,%eax
. Converting b83cb
from hexadecimal to decimal yields 754635
.
Running the program and entering 754635
prints out the flag.
Note that without decompressing using upx
, gdb would have been unable to display any assembly.
picoCTF{up><_m3_f7w_77ad107e}