My writeup for the National Cyber Scholarship Competition 2021
Download the file and find a way to get the flag.
Contents: program
This is another binary program, which when ran prints āIām not going to make it that easy for you.ā and exits:
My next step was to load it into gdb
(the standard GNU debugger), and place a breakpoint on main with b main
. I then started the program with r
and waited for the program to load and break at main. I then disassembled the instructions with disas
, which gave me the following:
Breakpoint 1, 0x00005555555547e7 in main ()
(gdb) disas
Dump of assembler code for function main:
0x00005555555547e3 <+0>: push %rbp
0x00005555555547e4 <+1>: mov %rsp,%rbp
=> 0x00005555555547e7 <+4>: sub $0x10,%rsp
0x00005555555547eb <+8>: movl $0x1,-0x4(%rbp)
0x00005555555547f2 <+15>: cmpl $0x539,-0x4(%rbp)
0x00005555555547f9 <+22>: jne 0x555555554807 <main+36>
0x00005555555547fb <+24>: mov -0x4(%rbp),%eax
0x00005555555547fe <+27>: mov %eax,%edi
0x0000555555554800 <+29>: call 0x5555555546aa <printFlag>
0x0000555555554805 <+34>: jmp 0x555555554813 <main+48>
0x0000555555554807 <+36>: lea 0x9a(%rip),%rdi # 0x5555555548a8
0x000055555555480e <+43>: call 0x555555554570 <puts@plt>
0x0000555555554813 <+48>: mov $0x0,%eax
0x0000555555554818 <+53>: leave
0x0000555555554819 <+54>: ret
End of assembler dump.
I am far from an assembly expert, but from my basic knowledge I can see it does some operations on the stack, does a compare and then a jne
(which jumps if the operands to the last compare call were not equal) to the end of the main function at +36, which appears to call puts and exit, which is probably what the program does by default. It completely skips over a call to the printFlag
function. I planned on fixing it so I would get the program into the printFlag
function so I set a breakpoint there with b printFlag
. In order to get into that function I stepped over the stack manipulation with nexti
a few times until I got to +22, when I jumped to the next instruction by calling jump *0x00005555555547fb
.
It successfully enters the printFlag
function, which appears to also have a early jump that skips most of the function (most of the disassembly has been omitted as it is a long function):
Dump of assembler code for function printFlag:
=> 0x00005555555546aa <+0>: push %rbp
0x00005555555546ab <+1>: mov %rsp,%rbp
0x00005555555546ae <+4>: sub $0x40,%rsp
0x00005555555546b2 <+8>: mov %edi,-0x34(%rbp)
0x00005555555546b5 <+11>: mov %fs:0x28,%rax
0x00005555555546be <+20>: mov %rax,-0x8(%rbp)
0x00005555555546c2 <+24>: xor %eax,%eax
0x00005555555546c4 <+26>: cmpl $0x539,-0x34(%rbp)
0x00005555555546cb <+33>: jne 0x5555555547cc <printFlag+290>
0x00005555555546d1 <+39>: movb $0x15,-0x20(%rbp)
0x00005555555546d5 <+43>: movb $0x70,-0x1f(%rbp)
0x00005555555546d9 <+47>: movb $0xe5,-0x1e(%rbp)
0x00005555555546dd <+51>: movb $0x64,-0x1d(%rbp)
0x00005555555546e1 <+55>: movb $0x7a,-0x1c(%rbp)
...
I used nexti
to execute each instruction until I got to +33, where the jen
instruction is. I wanted to override this so it would not jump and would print the flag. To do it slightly different I know that jen
jumps if the ZF
flag is not set (This wikibook is a great assembly resource). I printed out the flag register with print $eflags
and saw that it was not set, so I executed the following gdb script to set it, making the jne
not jump:
set $eflags |= (1 << 6)
the ZF
flag is at index 6, so I simply perform a bitwise operation to make sure it is on. I then ran c
to continue the program, which printed the following providing the flag:
(gdb) c
Continuing.
Flag: patchItFixIt