提示格式化字符串漏洞 简单介绍一下原理: 在写C语言时,不免经常使用printf函数,这个函数有一个很常见的用法:
a = 24; printf("%d岁,是学生",a);输出结果很显然是
24岁,是学生但是如果出现这么个情况:
a = "%p.%p.%p.%p." printf(a)它就会输出栈的后4个地址。
a = "%4$p" printf(a)单独输出第四个地址
a = "%4$s" printf(a)单独输出第四个地址里存的值
于是可以这样使用
gets(a) printf(a) addr = 0x114514 #填入你想要看的值的地址 io.sendline("%8$s"+p64(addr))"%8$s"中的8具体应该填几之后会讲到,总之通过这个代码可以得到你想要的地址中的值。
把程序丢进64位IDA,可以看到有一个read,一个printf。 然后之后是一个for循环,需要连续输入15个随机数,由于随机数和时间挂钩,输错一个就退出,基本不可能爆破了。 但是,我们都知道计算机的随机是伪随机,是通过算法选择一个种子,然后基于这个种子生成随机数,也就是说,如果我们可以获得这个随机数的种子,那这15个数就可以推算出来。 那注意力就要放在这两个函数上: 可以看到,它是先生成种子,然后进行的read和printf,最后再用srand使用这个种子。 也就是说我们利用printf的格式化字符串漏洞,是可以读到seed的值的。
先讲一下python脚本 seed_addr即seed的地址通过IDA获得,在main中双击seed可以得到 然后构造payload '%9s…‘是指读取后面第9个地址,至于为什么是第九个,是试出来的。 测试时输入’AAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.’ 会得到这样的结果: 可以看到之后第八个变量是0x4141414141414141即之前输入的AAAAAAAA。 所以,我们之前传的a前8位"AAAAAAA"(64位程序机器字长为8)被放在了第八个地址,那也就是说如果我printf(“AAAAAAAABBBBBBBB”)里面放8个A 8个B,那么前8个A会被存在printf后第八个地址,后8个B会被挤到第九个地址。 那就可以理解脚本中的payload:
payload = '%9$s....' + p64(seed_addr)'%9$s…'被放在第八个地址(后面补4个点是为了刚好占满8个字节),seed的地址存放在第九个地址,使得%9$s刚好读到seed的地址中的内容。
最后,读出返回的seed值,用u64解包。
然后是C脚本,用获得的seed,生成15个随机数,一定和程序用随机函数生成的15个数字相同。之后把获得的16个数按顺序粘贴进去就可以获得权限。
运行python脚本得到种子号1603170101
运行C脚本得到15个数(每个人每个时间都不一样)。 粘贴进去即可获得权限。 得到flag:SYC{FFFFFFmtttttt_ssssoooo_g0000d}