I love academic misconduct
Running the program directly will fail for all possible inputs:
Welcome to Secure Exam Browser
Enter Password: 123456
ERR: another process is running!
The problem lies in the op
function. We patch the caller function to skip over it:
.text:000000000000473C ; =============== S U B R O U T I N E =======================================
.text:000000000000473C
.text:000000000000473C
.text:000000000000473C ; bool obf::bool_functor<`anonymous namespace'::decode_flag(std::string const&)::{lambda(void)#11}::operator() const(void)::{lambda(void)#3}>::run()
.text:000000000000473C _ZN3obf12bool_functorIZZN12_GLOBAL__N_111decode_flagERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlvE9_clEvEUlvE1_E3runEv proc near
.text:000000000000473C ; DATA XREF: .data.rel.ro:0000000000008988↓o
.text:000000000000473C ; __unwind {
.text:000000000000473C endbr64
.text:0000000000004740 sub rsp, 8
.text:0000000000004744 call _Z2opv ; op(void)
.text:0000000000004749 test eax, eax
.text:000000000000474B setnz al
.text:000000000000474E add rsp, 8
.text:0000000000004752 retn
.text:0000000000004752 ; } // starts at 473C
.text:0000000000004752 _ZN3obf12bool_functorIZZN12_GLOBAL__N_111decode_flagERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlvE9_clEvEUlvE1_E3runEv endp
Replace the sub rsp, 8
instruction with ret
. Then, we can execute it correctly:
Welcome to Secure Exam Browser
Enter Password: 123456
Incorrect password!
Next, we find the Incorrect password!
string and its logic surround (somehow the logic is hidden from the decompiler of IDA):
.text:00000000000050D7 mov rdx, [rsp+58h+n] ; n
.text:00000000000050DC cmp rdx, [rsp+58h+var_30]
.text:00000000000050E1 jz short loc_50F8
.text:00000000000050E3
.text:00000000000050E3 loc_50E3: ; CODE XREF: main+B1↓j
.text:00000000000050E3 lea rsi, aIncorrectPassw ; "Incorrect password!\n"
.text:00000000000050EA lea rdi, _ZSt4cout@@GLIBCXX_3_4
.text:00000000000050F1 ; try {
.text:00000000000050F1 call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc ; std::operator<<<std::char_traits<char>>(std::ostream &,char const*)
.text:00000000000050F6 jmp short loc_5135
.text:00000000000050F8 ; ---------------------------------------------------------------------------
.text:00000000000050F8
.text:00000000000050F8 loc_50F8: ; CODE XREF: main+85↑j
.text:00000000000050F8 mov rsi, [rsp+58h+s2] ; s2
.text:00000000000050FD mov rdi, [rsp+58h+s1] ; s1
.text:0000000000005101 test rdx, rdx
.text:0000000000005104 jz short loc_510F
.text:0000000000005106 call _memcmp
.text:000000000000510B test eax, eax
.text:000000000000510D jnz short loc_50E3
Using pwndbg, we set a breakpoint at 0x50DC
which is main+128
, it shows the expected length of input:
───────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────────────────────────────────────────────────────────
► 0x5555555590dc <main+128> cmp rdx, qword ptr [rsp + 0x28] 0x6 - 0x2c EFLAGS => 0x293 [ CF pf AF zf SF IF df of ac ]
b+ 0x5555555590e1 <main+133> ✘ je main+156 <main+156>
0x5555555590e3 <main+135> lea rsi, [rip + 0xfc0] RSI => 0x55555555a0aa ◂— 'Incorrect password!\n'
So the flag length is 0x2c
. Input 44 A
and step through memcmp:
───────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────────────────────────────────────────────────────────
b+ 0x5555555590e1 <main+133> ✔ je main+156 <main+156>
↓
0x5555555590f8 <main+156> mov rsi, qword ptr [rsp + 0x20] RSI, [0x7fffffffe440] => 0x555555570c20 ◂— "K17{i_heard_that_it's_impossible_to_re_c++!}"
0x5555555590fd <main+161> mov rdi, qword ptr [rsp] RDI, [0x7fffffffe420] => 0x555555570b70 ◂— 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
0x555555559101 <main+165> test rdx, rdx 0x2c & 0x2c EFLAGS => 0x202 [ cf pf af zf sf IF df of ac ]
0x555555559104 <main+168> ✘ je main+179 <main+179>
► 0x555555559106 <main+170> call memcmp@plt <memcmp@plt>
s1: 0x555555570b70 ◂— 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
s2: 0x555555570c20 ◂— "K17{i_heard_that_it's_impossible_to_re_c++!}"
n: 0x2c
0x55555555910b <main+175> test eax, eax
0x55555555910d <main+177> jne main+135 <main+135>
The flag is K17{i_heard_that_it's_impossible_to_re_c++!}
.