刷题进行中
持续更新
强网
easyfuzz
当时还做了一个 Misc 嘻嘻
它最多输入 10byte 就是说
一开始我就疯狂手动尝试,发现输入九位字符的时候会被覆盖成 110000000,其他情况不管怎么输入都是九个零
又尝试胡乱打了几下发现同是九位,输入 asdf'fdd
就可以覆盖最高位的 0 了好神奇
又又再次多次尝试发现最后一位是 d,对应的最后一位就是1。同时只要输入是九位,不管输入的前两位怎么变,覆盖率前两位都是11。
所以说覆盖率后七位和输入的后七位一一对应。误打误撞知道最后一位是d,那我们只需要爆破一下中间的六位就行。
综上,我们只要保证一共输入九位,最后一位是d。只需要尝试枚举对应位值为0的位,对应位是1,那么就是已经找到了正确的值不需要改变了。
1 |
|
最后就暴力破解出来是 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 |
|
学会了个语法用字典来填充字符串,例如:
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
这个命令的作用如下:
tac
:tac
命令用于颠倒文本文件中的行。它以相反的顺序打印文件的行。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 |
|
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 |
|