前言 :
拖了有点久的东西,现在补上,上周末打了场护网杯,带着学弟们打,被虐的有点厉害。有一题我后来复现的时候才发现是一道之前在看雪上发现有人求助的一道题目,我当时还看了题解。。匆匆略过去了。。还没有好好看看程序的样子。有点可惜了呀。有八九百分呢。
正文 :
gettingstart :
好像比签到题做出来的人都多了。多的就不说了,把值给覆盖一下就行了,找-1在内存里的十六进制表示的话,去IDA里面找就行了,再不行就自己写一个程序看看。
1 | payload = 'A'*0x18 + p64(0x7FFFFFFFFFFFFFFF) + p64(0x3fb999999999999a) |
shoppingcart :
这题我是真佛了,我看了一早上。。我愣是没看出来哪里有漏洞,后来发现就一个数组越界漏洞的时候我的心情真的跟吃了屎一样难受。可坑死我了,而且堆部分的东西压根没有用,没有用你搞一个是什么意思啊。。我佛了,没意思啊。
漏洞出现在编辑商品的函数上:
1 | unsigned __int64 edit_good() |
而且还会打印地址,可以泄漏地址。而且出题人考虑到加了PIE,还特地在0x202068
存储了所在地址的十六进制。所以可以先泄漏此处的地址得到程序的基地址。然后再去修改此处为第一阶段存钱得到的堆地址处:
1 | .bss:0000000000202140 unk_202140 db ? ; ; DATA XREF: sub_D81+B6↑o |
然后再去修改上面堆地址处的内容为strtoul
函数的got表的地址,然后再次编辑可以泄漏出strtoul
的地址,从而泄漏libc的地址,再次编辑为system
函数的地址,就可以getshell了。又或者。
先将unk_202140处修改,也就是将:
1 | .bss:00000000002020A0 byte_2020A0 db 0A0h dup(?) ; DATA XREF: sub_D81+62↑o |
处修改为unk_202140处,再修改byte_2020A0,也就是堆内容处为strtoul
got表地址,再编辑为system函数。
EXP :
1 | from pwn import * |
huwang :
这题就更骚了,堆完全用不到,太骚了,那你特么的出个堆不累吗你。利用在666的md5加密轮数函数里面,叫你猜md5。
这里的函数:
1 | HIDWORD(v2) = open("/tmp/secret", 513); |
open函数还有第二、三个参数。来看看官方说法:
1 | int open(constchar*pathname,intflags); |
第二个参数的flags用于指定文件的打开/创建模式,这个参数可由以下常量(定义于fcntl.h)通过逻辑位或逻辑构成。fcntl.h函数源代码
1 | O_RDONLY只读模式 |
打开/创建文件时,至少得使用上述三个常量中的一个。以下常量是选用的:
1 | O_APPEND每次写操作都写入文件的末尾 |
看题目用了513的十进制数,转化为八进制就是:
1 | HIDWORD(v2) = open("/tmp/secret", 01001); |
看源代码:
1 | #define O_WRONLY 01 |
就是这两者或之后得到的。而O_TRUNC是会清空文件全部内容的,所以说当运行一次程序的同时再运行第二次程序,那么第二次程序打开该文件的时候该文件就是空的,那么我们就能拿到空文件md5加密后的内容了。这里用加密-1轮就可以使程序运行很久。
1 | >>> import md5 |
之后进入的函数就很明显有栈溢出、格式化字符串的漏洞了。这里用格式化泄漏canary的值,不过这里的canary的值最低位是00,如果不覆盖的话是leak不了的,所以还要多覆盖一位,再减去0x41即可。后面用栈溢出leak出libc,重新执行程序,我写的是回到该函数的入口,但是这里如果直接返回首部会报错,因为有一些寄存器的值不对应,所以我们在此之前还需要还原某些寄存器的值。看一下入口处的汇编:
1 | .text:000000000040101C ; __unwind { |
这里看到有一个:
1 | mov [rbp+var_228], rdi |
所以跟踪得到此时rdi的值是0x603030。所以在溢出时还原rdi的值就可以重新执行该函数了。
EXP :
1 | from pwn import * |
six :
就是这道题。。我之前还在看雪上见过这题。。但是就只是看了一下题解,嫌麻烦就是没有看看程序内部。。难受啊。。我看了的话就有很多分了。
1 | unsigned __int64 sub_9CA() |
先mmap了两块内存存储在dest、qword_202098的bss段上。
这里的一个知识点:
mmap的地址是urandom来的,但是不满足mmap要求时,会随机分配这个地址,申请两块同样大小的mmap内存时,当随机分配时二者相邻,且用作栈的地址是低地址。
在看看后面:
1 | puts("Show Ne0 your shellcode:"); |
输入六个字节的shellcode,且必须是三个奇数三个偶数,且每个字节都不同。
跟踪看看执行到输入的shellcode之前是怎样的:
1 | 0x7f010023f000 mov rsp, rdi |
只有一个rsp的值,别的寄存器都被清空了。构造的shellcode只能有6个字节。由于寄存器都清零,这里我们想到可以使用0号系统调用read函数,由于上面说的有两块mmap内存连续的情况,所以可以从rsp开始写到rip处,继续构造shellcode。
这里可以构造6个字节的shellcode:
1 | asm(''' |
伪造大小rdx时,rdx不能太大。所以用edx和esi。
EXP :
1 | from pwn import * |
calendar :
这题关于House of Roman,以后再来补。
EXP :
1 | from pwn import * |
总结 :
还是得好好努力,差距还是有点大,加油。