一、概念以及背景:
首先厘清概念:什么是栈溢出?什么是pwn?什么是网络安全?
大多数人首先是遇到网络安全问题、工作需要才遇到这些,而不是自然而然地从学校了解,即便在校学生,当初也不都是出于自己的意愿选择了网络安全相关专业,所以我们先从问题出发,分别了解这些名词。
什么是网络安全?!
2017年5月12日起,全球范围内爆发基于Windows网络共享协议进行攻击传播的蠕虫恶意代码,这是不法分子通过改造之前泄露的NSA黑客武器库中“永恒之蓝”攻击程序发起的网络攻击事件。五个小时内,包括英国、俄罗斯、整个欧洲以及中国国内多个高校校内网、大型企业内网和政府机构专网中招,被勒索支付高额赎金才能解密恢复文件,对重要数据造成严重损失。[1]首先我们能从中确认,没有网络安全就会在遇到网络有关的问题时,出现不可挽回的经济损失;从事件影响里能看到多国的相关单位包括政府、银行、电力系统、通讯系统、能源企业、机场等重要基础设施都被波及,律师事务所DLA Piper的多个美国办事处也受到影响。中国亦有跨境企业的欧洲分部中招。
2024年7·19微软蓝屏事件是指当地时间2024年7月19日美国网络安全企业“群集打击”(CrowdStrike)软件出现问题引发的操作系统蓝屏、全球宕机事件 。此次微软蓝屏波及不少国家地区,影响全球近千万台使用Windows的设备,导致航空公司、银行、电信公司和媒体、健康医疗等各个行业陷入混乱 。“微软蓝屏”登上热搜,不少打工人晒出电脑蓝屏画面,戏称“感谢微软,提前放假”[2]。从事件结果我们了解到该事件已经造成了全球性的影响:多国石油、天然气、电力、股票、货币和债券交易商都在19日当天难以正常展开交易。运营伦敦证券交易所的LSEG集团表示,旗下Workspace新闻和数据平台遭遇宕机,影响了全球用户。欧洲能源交易所称,使用其Trayport电力和天然气交易平台的客户在交易中遇到了问题。石油巨头壳牌、英国石油和维多能源集团的至少六名交易消息人士表示,业务受到了影响。[3]
从这跨越7年的事件中,我们能总结到网络安全会影响到多方面如经济、金融、股票、债券交易、重要基础设施、舆论、用户使用感受等。
什么是栈溢出?!
对于永恒之蓝,我们二进制的网安研究人员能注意到永恒之蓝利用的就是445端口的SMB服务,缓冲区溢出漏洞[4-6]。EternalBlue达到其攻击目的事实上利用了3个独立的漏洞:第一个也就是CVE-2017-0144被用于引发越界内存写;第二个漏洞则用于绕过内存写的长度限制;第三个漏洞被用于攻击数据的内存布局。
栈溢出漏洞就是缓冲区溢出漏洞的一种,在现实世界中栈溢出漏洞越来越少,主要出现在iot固件中,linux以及Windows等平台下的已经很少了。但只要他出现了,就其危害性依然很严重,很容易导致RCE。如CVE-2023-27021:是路由器的栈溢出漏洞,攻击者可深入利用并实现RCE。
在Web应用程序中,RCE(远程代码执行)攻击确实存在绕过防火墙和WAF(Web应用程序防火墙)的可能性,在二进制漏洞像CVE-2023-27997 ,其严重性得分为 9.8 分(满分 10 分),则让300000 台设备受到严重影响,Bishop Fox 说:“尽管已经呼吁所有用户快速修补漏洞,但仍有 30 多万FortiGate 防火墙设备容易受到攻击。"[9],在奇安信的技术研究院的研究报告中点出“该漏洞可以实现栈上越界写”“劫持RIP”"ROP"并评价道“该漏洞与去年的CVE-2023-27997
XOR导致的堆溢出漏洞类似,都是看起来比较鸡肋的溢出漏洞,利用过程比较Trick,更像是一道CTF题目。但是与传统攻击堆管理器的CTF题目相比,真实漏洞更多的需要借助上下文的结构体和代码逻辑完成利用。”[10]
什么是pwn!
PWN(也称为pwn)是黑客和信息安全领域中的一种术语,通常指通过利用系统或设备的漏洞来攻破或控制它们。这个词语源自英文单词“own”,意为“拥有”,在黑客文化中象征着成功实施攻击并获得目标系统的控制权。
在CTF比赛中,栈溢出攻击的工作流程如下:
-
找到漏洞:首先需要识别出目标系统中的栈缓冲区溢出漏洞。这通常通过分析程序的源代码、二进制文件。
-
构造攻击载荷,覆盖返回地址:攻击者会编写一段特定的恶意代码,这段代码包含在栈上执行的指令。这些指令可以是任意的汇编语言指令,也可以是系统调用、ROP、gadget等。
-
执行攻击代码:在CTF比赛中,选手们写出Python脚本,一般命名为exp.py,运行后就得到目标系统的控制权。
二、基本知识记录
Pwntools功能详解与应用案例
安装如下
#pwntools
sudo apt-get update
sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade pwntools
#Ubuntu20以上自带gdb:
mkdir $HOME/Documents/GDB-Plug-in
cd $HOME/Documents/GDB-Plug-in
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
git clone https://github.com/scwuaptx/Pwngdb.git
cp $HOME/Documents/GDB-Plug-in/Pwngdb/.gdbinit ~/ #或者自己改
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
#LibcSearcher
git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
python setup.py develop
加载Pwndbg插件:在GDB中,你需要加载Pwndbg插件。输入以下命令加载Pwndbg:
source /path/to/pwndbg/gdbinit.py
/path/to/pwndbg`是你安装Pwndbg的路径。
(一)pwntools
简介和参考网址(官网和翻译)
Pwntools是一个用于CTF(Capture The Flag)和漏洞利用开发的Python库,它简化了与二进制文件、网络连接、调试和shellcode生成的交互。
官网中文文档地址:https://pwntools-docs-zh.readthedocs.io/zh-cn/dev/intro.html、https://blog.csdn.net/kelxLZ/article/details/123152529(翻译了https://github.com/Gallopsled/pwntools-tutorial)
以下是一些常见的Pwntools函数及其使用方法:
1.管道-输入输出、打包、进程和连接
管道是方便高效的I/O包装器,里面包含了你需要执行的大多数类型的I/O。
1.1基础IO模块:接收数据
-
recv(numb = 2048, timeout = dufault)
: 接收任意数量的字符串,长度为numb,单位是字节,timeout指定超时 -
recvline(keepends=True, timeout=default)
: 接受一行数据直到到回车\n,timeout指定超时;keepends=False不保留结尾的\n -
recvlines(N)
:接收 N(数字) 行输出 -
recvuntil("dlimes",drop=fasle)
: 接受数据知道我们设置的标志出现 -
recvall()
: 接受到EOF -
recvrepeat(timeout = default)
: 接收到EOF或timeout
1.2基础IO模块:发送数据
-
sendline(data)
: 发送一行数据,并在数据末尾添加换行符。例如,sendline("Hello, world!")
表示发送一行数据“Hello, world!”。换言之:· 发送payload,并进行换行(末尾**\n**) =send( )+ \n -
send(data)
: 发送数据,不添加换行符。换言之:· 发送payload -
sendafter(some_string, payload)
: 接收到 some_string 后, 发送你的 payload
1.3打包和解包
-
p32(x)
: 打包一个整数到四个字节。 -
u32(x)
: 解包四个字节到一个整数。 -
p64(x)
: 打包一个整数到八个字节。 -
u64(x)
: 解包八个字节到一个整数。
>>>importstruct
>>>p32(0xdeadbeef) == struct.pack('I', 0xdeadbeef)
True
>>>u32(b'abcd') == struct.unpack('I', b'abcd')[0]
True
>>>u8(b'A') == 0x41
True
1.4连接:进程操作
-
process(image)
: 创建并启动一个新的进程。 -
remote(url, port)
: 连接到远程服务器并执行指定的命令。 -
interactive()
:进行回话互动
2.ELF文件操作
2.1elf操作
-
ELF(image)
: 加载并操作ELF文件。from pwn import * e = ELF('/bin/bash') # [*] '/bin/bash' # Arch: amd64-64-little # RELRO: Partial RELRO # Stack: Canary found # NX: NX enabled # PIE: No PIE # FORTIFY: Enabled
e.address = 0x12340000 ,改变ELF文件的基址(比如为ASLR做调整)是非常直接和简单的。
-
· 使用符号表
· symbols['a_function'] 找到 a_function 的地址 ,列出所有已知的符号,包括下面的符号。优先考虑PLT条目,而不是GOT条目。
· 程序开始时plt=symbols
· 我想,假如有个自定义的函数a_function,这里的symbols就能体现作用了
· got['a_function'] 找到 a_function的 got
· plt['a_function'] 找到 a_function 的 plt
· functions['list_all_jobs']只包含函数符号表(需要DWARF符号表)
· next(e.search(b"some_characters")) 找到包含 some_characters(字符串,汇编代码或者某个数值)的地址.
或者
for address in e.search('/bin/sh\x00'): print hex(address)
· bss() 得bss段的地址
补充:启动一个调试器,并将其连接到ELF上。这在测试shellcode时是非常有用的,不需要用C语言包装器来加载和调试它。
>>> io = elf.debug() # vs >>> io = gdb.debug(elf.path)
2.2文件I/O:可以对elf文件进一步操作
from pwn import *
write('filename', 'data1')
read('filename')
# 'data1'
read('filename', 1)
# 'd'
2.3DynELF
-
DynELF(image)
: 动态分析ELF文件,获取信息如堆栈偏移等。DynELF的基本利用模板为:
p= process('./binary') #32位的elf文件 def leak(address): #各种预处理 payload = "xxxxxxxx" + address + "xxxxxxxх" p.send(payload) #能各种处理 data = p.recv(4) log.debug("%#x =>%s"%(address,(data or '').encode('hex'))) return data d = DynELF(leak, elf=ELF("./binary"))#初始化DynELF模块 systemAddress = d.lookup('system','libc') #在libc文件中搜赛system函数的地址
感觉已经通过LibcSearcher替代了。
3汇编和反汇编:shellcraft
-
asm(data, arch)
: 将字节字符串反汇编为可读的汇编代码。asm(pwnlib.shellcraft.thumb.linux.sh(), arch="thumb") # 生成执行sh的shellcode并编译
# 可以将thumb换成对应cpu
# 读取flag并输出到标准输出pwnlib.shellcraft.i386.linux.cat("flag", fd=1)
# 使用forkbomb破坏系统(慎用)pwnlib.shellcraft.i386.linux.forkbomb()
shellcraft模块是shellcode的模块,包含一些生成shellcode的函数
asm()函数接收一个字符串作为参数,得到汇编码的机器代码。
例:
-
asm('mov eax, 0')
-
'\xb8\x00\x00\x00\x00'
摘取官网:
>>>asm('nop')
b'\x90'
>>>asm('nop', arch='arm')
b'\x00\xf0 \xe3'
提醒:asm会受context的设置影响
-
-
disasm(data, arch)
: 将字节字符串汇编为可读的汇编代码
4环境和调试:
4.1指定libc版本运行pwn题 or 使用patchelf
from pwn import *
libc_path = "/usr/local/libc/libc-2.23.so"
ld_path = "/usr/local/libc/ld-2.23.so"
p = process([ld_path, "./prog"], env={"LD_PRELOAD":libc_path})
libc模块的使用/libcsearcher的使用:
libc.dump('execve') 得libc里’execve’和和基地址的偏移
#elf.symbol 等 多个去寻址
4.2设置context
context(arch='arm', os='linux', endian='big', word_size=32,log_level = 'debug')
context.terminal = ['tmux','splitw','-h']
# 设置成debug,pwntools会将所有io数据等输出,方便编写poc的时候进行调试,而arch可以设置攻击目标的指令构架。
一般来说我们设置context只需要简单的一句话:
context(os='linux', arch='amd64', log_level='debug')
1.os是设置系统为Linux系统
2.arch是设置架构为amd64,可以简单的认为设置为64位的模式,32位对应'i386' 3.log_level设置日志输出等级为debug,这句话在调试的时候一般会设置,这样pwntools会将完整的io过程都打印下来,使得调试更加方便,可以避免在完成CTF题目时出现一些和IO相关的错误
4.3gdb调试:
有关gdb命令请详见第二节:(二)GDB以及一些插件的命令,还有gdb脚本的编写。
1、GDB下启动一个进程,一句话:io = gdb.debug("/bin/bash", gdbscript='continue')
2、附加到一个正在运行的进程
>>> io = process('binary')
>>> gdb.attach(io, gdbscript='continue')
3、远程服务器
想调试的二进制文件运行在一个远程服务器上,只要服务器在当前机器上运行,调试你所连接的进程(而不是服务器本身)也可以完成。
socat = process(['socat', 'TCP-LISTEN:4141,reuseaddr,fork', 'EXEC:binary -i'])
4、调试异构架构
pwntools调试异构架构(如ARM或PowerPC)很容易
>>> context.arch = 'arm'
>>> elf = ELF.from_assembly(shellcraft.echo("Hello, world!\n") + shellcraft.exit())
>>> process(elf.path).recvall()
b'Hello, world!\n'
5、调试时附加环境变量
>>> io = gdb.debug(['bash', '-c', 'echo $HELLO'], env={'HELLO': 'WORLD'})
>>> io.recvline()
b'WORLD\n'
ROP模块
寻找gadget可以使用ROPgadget、Xgadget以及ropper
ROP对象实现了getattr的功能,可以直接通过func call的形式来添加函数,rop.read(0, elf.bss(0x80))实际相当于rop.call('read', (0, elf.bss(0x80)))。 通过多次添加函数调用,最后使用str将整个rop chain dump出来就可以了。
call(resolvable, arguments=()) : 添加一个调用,resolvable可以是一个符号,也可以是一个int型地址,注意后面的参数必须是元组否则会报错,即使只有一个参数也要写成元组的形式(在后面加上一个逗号)
chain() : 返回当前的字节序列,即payload
dump() : 直观地展示出当前的rop chain
raw() : 在rop chain中加上一个整数或字符串
search(move=0, regs=None, order=’size’) : 按特定条件搜索gadget
unresolve(value) : 给出一个地址,反解析出符号
elf.address = 0xff000000#设置elf基地址
rop = ROP(elf)#创建ROP对象
rop.gadgets#查看所有gadgets ,
#将原始数据添加到ROP栈中:
rop.raw(0xdeadbeef)
rop.raw(0xcafebabe)
rop.raw('asdf')
#输出ROP栈:
print(rop.dump())
# 0x0000: 0xdeadbeef
# 0x0004: 0xcafebabe
# 0x0008: b'asdf' 'asdf'
#-------------------------------#
#想从它那里得到原始字节。我们可以使用byte()方法来实现这个功能:
print(hexdump(bytes(rop)))
# 00000000 ef be ad de be ba fe ca 61 73 64 66 │····│····│asdf│
# 0000000c
#-------------------------------#
#⭐⭐⭐⭐⭐调用任意函数⭐⭐⭐⭐⭐:
elf = ELF('/bin/sh')
rop = ROP(elf)
rop.call(0xdeadbeef, [0, 1])
print(rop.dump())
# 0x0000: 0xdeadbeef 0xdeadbeef(0, 1, 2, 3)
# 0x0004: b'baaa' <return address>
# 0x0008: 0x0 arg0
# 0x000c: 0x1 arg1
#⭐⭐使用函数名来调用函数⭐⭐:你的库在其GOT/PLT中有你想调用的函数,或者有二进制的符号,你可以直接调用函数名。
context.binary = elf = ELF('/bin/sh')
rop = ROP(elf)
rop.execve(0xdeadbeef)
print(rop.dump())
# 0x0000: 0x61aa pop rdi; ret
# 0x0008: 0xdeadbeef [arg0] rdi = 3735928559
# 0x0010: 0x5824 execve
#⭐⭐多个elf:一个使用/bin/sh以及其libc的例子。
context.binary = elf = ELF('/bin/sh')
libc = elf.libc
elf.address = 0xAA000000
libc.address = 0xBB000000
rop.rax
# Gadget(0xaa00eb87, ['pop rax', 'ret'], ['rax'], 0x10)
rop.rbx
# Gadget(0xaa005fd5, ['pop rbx', 'ret'], ['rbx'], 0x10)
rop.rcx
# Gadget(0xbb09f822, ['pop rcx', 'ret'], ['rcx'], 0x10)
rop.rdx
# Gadget(0xbb117960, ['pop rdx', 'add rsp, 0x38', 'ret'], ['rdx'], 0x48)
#⭐:rax和rbx的gadgets是在主二进制文件中(0xAA…),而后两个是在libc(0xBB…)。
#⭐⭐更复杂的函数调用:
rop.memcpy(0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc)
print(rop.dump())
# 0x0000: 0xbb11c1e1 pop rdx; pop r12; ret
# 0x0008: 0xcccccccc [arg2] rdx = 3435973836
# 0x0010: b'eaaafaaa' <pad r12>
# 0x0018: 0xaa0061aa pop rdi; ret
# 0x0020: 0xaaaaaaaa [arg0] rdi = 2863311530
# 0x0028: 0xaa005f73 pop rsi; ret
# 0x0030: 0xbbbbbbbb [arg1] rsi = 3149642683
# 0x0038: 0xaa0058a4 memcpy
#⭐⭐获取一个shell:当我们了解了pwntools的ROP功能时,获得一个shell是很容易的!我们直接调用execve,并从内存中的某个地方找到一个"/bin/sh/x00 "的实例作为第一个参数传递进去。
context.binary = elf = ELF('/bin/sh')
libc = elf.libc
elf.address = 0xAA000000
libc.address = 0xBB000000
rop = ROP([elf, libc])
binsh = next(libc.search(b"/bin/sh\x00"))
rop.execve(binsh, 0, 0)
其他功能:
misc/crypto/简单的re/auto stackoverflow fuzz:简单且实用的功能
1、auto
stackoverflow fuzz:样例生成,用法:
cyclic(0x100) # 生成一个0x100大小的pattern,即一个特殊的字符串
cyclic_find(0x61616161) # 找到该数据在pattern中的位置
cyclic_find('aaaa') # 查找位置也可以使用字符串去定位
比如,我们在栈溢出的时候,首先构造cyclic(0x100),或者更长长度的pattern,进行输入,输入后pc的值变味了0x61616161,那么我们通过cyclic_find(0x61616161)就可以得到从哪一个字节开始会控制PC寄存器了,避免了很多没必要的计算。
2、哈希和编码
Base64
'hello' == b64d(b64e('hello'))
Hashes
md5sumhex('hello') == '5d41402abc4b2a76b9719d911017c592'
write('file', 'hello')
md5filehex('file') == '5d41402abc4b2a76b9719d911017c592'
sha1sumhex('hello') == 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
URL Encoding
urlencode("Hello, World!") == '%48%65%6c%6c%6f%2c%20%57%6f%72%6c%64%21'
Hex Encoding
enhex('hello')
# '68656c6c6f'
unhex('776f726c64')
# 'world'
pwntools简单模板:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *
# 配置部分
context.arch = 'amd64' # 或 'i386'
context.log_level = 'debug' # 或 'info', 'error'
execve_file = './target_executable' # 目标可执行文件路径
libc_file = '/path/to/libc.so.6' # libc文件路径
host = 'target_ip' # 目标IP
port = target_port # 目标端口
# 信号处理
for sig in [signal.SIGINT, signal.SIGHUP, signal.SIGTERM]:
signal.signal(sig, lambda signum, frame: exit(0))
# 主逻辑
if __name__ == '__main__':
if args.LOCAL:
io = process(execve_file)
else:
io = remote(host, port)
if args.GDB:
gdb.attach(io, gdbscript='''...''') # GDB脚本
# 栈溢出部分
overflow_offset = 0x80 # 假设偏移量为0x80
return_address = 0x00400596 # 假设的返回地址
# 构造栈溢出payload
payload_overflow = flat(
'A' * overflow_offset, # 填充字符
return_address # 返回地址
)
# 发送栈溢出payload
io.recvuntil('...')
io.sendline(payload_overflow)
# 格式化字符串部分
format_string_offset = 0x10 # 假设格式化字符串的偏移量
target_address = 0x00400500 # 假设要修改的目标地址
target_value = 0xdeadbeef # 假设要写入的值
# 构造格式化字符串payload
payload_format_string = flat(
p32(target_address), # 要写入的地址
'%{}c'.format(target_value & 0xffff), # 用于写入低16位的值
'%{}$hn'.format(format_string_offset) # 用于写入到指定地址
)
# 发送格式化字符串payload
io.recvuntil('...')
io.sendline(payload_format_string)
# 交互模式
io.interactive()
bug整理
1、作者做题中遇到过因为脚本里写有中文而不能运行的情况,此时把“# - coding:utf-8 --”复制到开头第一行即可
2、python3的 byte类型和python2的不一样,前者发送的数据都要加b,如· sendline(b"echo hello") 发送payload,并进行换行(末尾**\n**;· recvuntil(b',');sh.recvline(timeout=1);· send(b'string'),
如果是python2的脚本可以在文件首行添加:
#!/usr/bin/python2
# -- coding:utf-8 --
3、接收不到的问题:
send发送的,有时候会接收不了。(改成sendline)
有时候是sendline发送的,要注意回车。
4、麻烦:
关于Python3的bytes
对象,有一个值得一提的 “麻烦”。当对它们进行迭代时,你会得到整数,而不是bytes
对象。这是与Python2的巨大差异,也是一个主要的烦恼。
见此文:https://blog.csdn.net/kelxLZ/article/details/123152529
字符操作:
-
ordlist() 将字符串内容转换成ascii码,以列表的形式
-
unordlist() 将列表中的ascii码转换成字符串
5、以上关于pwntools的还有日志没有写
(二)GDB以及一些插件的命令
通过网盘分享的文件:pwndbg食用方式.pdf
链接: https://pan.baidu.com/s/1vA20_JU84xJZk9qk5wz7UQ?pwd=ur2x 提取码: ur2x
pwndbg简介:Exploit Development and Reverse Engineering with GDB Made Easy = 利用GDB开发和逆向工程变得容易
GDB及插件的常见命令的表格
gdb+pwndbg/gef +pwngdb
命令 | 缩写 | 效果 | 备注 |
---|---|---|---|
gdb <*pid> | 添加新程序 | ||
gdb attach | 负载运行的程序 | ||
set args <*argv> | 设置程序运行参数 | ||
show args | 查看设置好的运行参数 | ||
quit | q | 退出gdb | |
symbol | sy | 导入符号表 | |
info <*b> | i | 查看程序的状态/*查看断点 | |
list | l | 显示源代码(debug模式) | |
display | disp | 跟踪查看某个变量 | |
start | s | 启动程序并中断在入口debug模式停在main(),否则停在start() | |
run | r | 直接运行程序直到断点 | |
continue | c | 暂停后继续执行程序 | |
next | n (ni) | 单步步过 | |
step | s (si) | 单步步入,函数跟踪 | |
finish | fin | 跳出,执行到函数返回处 | |
break /* | b | 下断点 | |
watch | 下内存断点并监视内存情况 | ||
p | 打印符号信息(debug模式) | ||
info registers | i r a | 查看所有寄存器 | |
i r <esp/ebp..> | 查看某个寄存器 | ||
set $esp = 0x01 | 修改某个寄存器的值 | ||
reg查看内存布局 | 查看所有寄存器的值 | ||
p $寄存器代号 | 查看指定寄存器的值: | ||
i proc mappings | 查看内存布局 | ||
frame | f | 查看栈帧 | |
backtrace | bt | 查看堆栈情况 | |
b *地址 | 在指定地址设置断点: | ||
b 函数名 | 在指定函数设置断点: | ||
heap | 查看分配的chunk | ||
vis | 更漂亮的显示堆块 | ||
vmmap | 查看内存分配情况 | ||
bin | 查看 Bin 情况 | ||
x /<n/f/u> | 显示内存信息,具体用法附在下面 | ||
libcsearch '字符串'context | 查看libc动态地址****查找字符串所在地址:打印 pwnbdg 页面信息 | ||
dps | 优雅地显示内存信息 | ||
disassemble | 打印函数信息 | ||
vmmap | 显示程序内存结构 | ||
search <*argv> | 搜索内存中的值输入 search -h 可查询用法 | ||
checksec | 查看程序保护机制 | ||
parseheap | 优雅地查看分配的chunk | ||
aslr <on/off> | 打开/关闭 ASLR 保护 | ||
pshow | 显示各种踏板选项和其他设置 | ||
dumpargs | 显示在调用指令处停止时传递给函数的参数 | ||
dumprop | 显示特定内存范围内的所有ROP gadgets | ||
elfheader | 从调试的elf文件获取头信息 | ||
elfsymbol | 从ELF文件获取非调试符号信息 | ||
procinfo | 显示来自/proc/pid的各种信息 | ||
readelf | 从elf文件获取头信息 |
pwndbg
Start Commands | 中文描述 |
---|---|
attachp | 附加到指定的进程ID、进程名称或设备文件。 |
entry | 从调试程序的入口点地址开始执行。 |
sstart | 'tbreak __libc_start_main; run' 的别名。 |
start [main, init] | 在最方便的位置开始调试程序,停止在第一个位置。 |
Step/Next/Continue Commands | 中文描述 |
nextcall | 在下一个调用指令处中断。 |
nextjmp [nextjump] | 在下一个跳转指令处中断。 |
nextproginstr | 在属于正在运行程序的下一个指令处中断。 |
nextret | 在下一个返回或类似指令处中断。 |
nextsyscall [nextsc] | 在下一个不带分支的系统调用处中断。 |
stepover [so] | 在此指令后的指令处中断。 |
stepret | 通过'步进'到它处中断下一个返回或类似指令。 |
stepsyscall [stepsc] | 通过带分支的系统调用处中断下一个系统调用。 |
stepuntilasm | 在下一个匹配的指令处中断。 |
xuntil | 继续执行,直到到达指定的地址或函数。 |
Context Commands | 中文描述 |
context [ctx] | 打印当前的寄存器、指令和栈上下文。 |
contextoutput [ctx-out] | 设置上下文部分的输出。 |
contextunwatch [ctx-unwatch, cunwatch] | 移除之前添加的用于监视的表达式。 |
contextwatch [ctx-watch, cwatch] | 添加一个用于上下文显示的表达式。 |
regs | 打印所有寄存器并增强信息。 |
Heap Commands | 中文描述 |
---|---|
arena | 打印一个arena的内容。 |
arenas | 列出进程的所有arenas。 |
bins | 打印一个arena的所有bin及其线程的tcache。 |
fastbins | 打印arena的快速bin。 |
find_fake_fast | 查找与指定地址重叠的假快速或tcache块。 |
heap | 迭代打印堆上的块。 |
heap_config | 显示与堆相关的配置。 |
hi | 在所有堆中搜索地址是否属于一个块,如果是,打印该块。 |
largebins | 打印arena的大块。 |
malloc_chunk | 打印一个块。 |
mp | 打印mp_结构的属性。 |
smallbins | 打印arena的小块。 |
tcache | 打印线程的tcache内容。 |
tcachebins | 打印tcache的内容。 |
top_chunk | 打印与arena的顶块相关的信息。 |
try_free | 检查如果用给定的地址调用free会发生什么。 |
unsortedbin | 打印arena的未排序bin的内容。 |
vis_heap_chunks | 显示堆上的块。 |
Breakpoint Commands | 中文描述 |
---|---|
breakrva [brva] | 在PIE基址的RVA处设置断点。 |
ignore | 将断点编号N的忽略计数设置为COUNT。 |
Memory Commands | 中文描述 |
distance | 打印两个参数之间的距离,或者打印地址的页基的偏移量。 |
hexdump | 在指定的地址或模块名称处进行十六进制转储。 |
leakfind | 尝试查找给定起始地址的泄漏链。 |
memfrob | 给内存区域的内存进行加密(异或操作)。 |
mmap | 调用mmap系统调用,并打印其结果地址。 |
mprotect | 调用mprotect系统调用,并打印其结果值。 |
p2p | 指针到指针链搜索。在给定的映射中搜索所有指向指定映射的指针。 |
probeleak | 指针扫描以查找可能的偏移泄漏。 |
search | 在内存中搜索字节序列、字符串、指针和整数值。 |
telescope | tel | 从指定的地址递归地解引用指针。 |
vmmap [lm, address, vprot, libs] | 打印虚拟内存映射页面。 |
vmmap_add | 添加虚拟内存映射页面。 |
vmmap_clear | 清除vmmap缓存。 |
vmmap_load | 从ELF文件加载虚拟内存映射页面。 |
xinfo | 显示指定地址相对于各种有用位置的偏移量。 |
xor | 在给定的地址处用键进行异或操作。 |
Stack Commands | 中文描述 |
canary | 打印当前栈金丝雀|canary。 |
retaddr | 打印包含返回地址的栈地址。 |
stack | 在指定计数和偏移处对栈数据进行解引用。 |
stackf | 在指定计数和偏移处对栈数据进行解引用,并打印整个栈帧。 |
Register Commands | 中文描述 |
cpsr [xpsr, pstate] | 打印ARM CPSR或xPSR寄存器。 |
fsbase | 打印FS基址。也见$fsbase。 |
gsbase | 打印GS基址。也见$gsbase。 |
setflag [flag] | 修改标志寄存器。 |
Process Commands | 中文描述 |
killthreads | 杀死所有或指定的线程。 |
pid [getpid] | 获取PID。 |
procinfo | 显示关于运行进程的信息。 |
Linux/libc/ELF Commands | 中文描述 |
argc | 打印参数的数量。 |
argv | 打印argv的内容。 |
aslr | 检查当前ASLR状态,或者打开/关闭它。 |
auxv | 打印Auxiliary ELF Vector的信息。 |
elfsections | 打印ELF头中的段映射。 |
envp [env, environ] | 打印环境变量。 |
errno | 将errno(或参数)转换为其字符串表示。 |
got | 显示全局偏移表(GOT)的状态。 |
gotplt | 如果存在,打印.got.plt段中的任何符号。 |
linkmap | 显示Link Map的状态。 |
onegadget | 显示onegadget。 |
piebase | 从PIE基址计算RVA的虚拟地址。 |
plt | 如果存在,打印.plt段中的任何符号。 |
threads | 列出属于选定子进程的所有线程。 |
tls | 打印当前线程本地存储(TLS)的基址。 |
track-got | 控制GOT跟踪。 |
track-heap | 管理堆跟踪器。 |
Disassemble Commands | 中文描述 |
emulate | 类似于nearpc,但会从当前$PC处向前模拟指令。 |
nearpc [pdisass, u] | 在指定地址附近进行反汇编。 |
Misc Commands | 中文描述 |
---|---|
asm | 将shellcode汇编成字节。 |
break-if-not-taken | 在分支未执行时中断。 |
break-if-taken | 在分支执行时中断。 |
checksec | 使用checksec 打印二进制文件的安全设置。 |
comm | 在汇编代码中添加注释。 |
cyclic | 创建/查找循环模式。 |
cymbol | 在C语言中添加、显示、加载、编辑或删除自定义结构。 |
down | 选择并打印由当前栈帧调用的栈帧。 |
dt | 输出类型(如ucontext_t)的信息。 |
dumpargs [args] | 打印确定的调用指令的参数。 |
getfile | 获取当前文件。 |
ipi | 启动一个交互式的IPython提示符。 |
patch | 用给定的代码或字节修改指定的指令。 |
patch_list | 列出所有补丁。 |
patch_revert | 在给定的地址处撤销补丁。 |
plist | 转储链表的元素。 |
sigreturn | 显示特定地址处的SigreturnFrame。 |
spray | 用cyclic()生成的值填充内存。 |
tips | 显示提示。 |
up | 选择并打印调用当前栈帧的栈帧。 |
valist | 转储va_list的参数。 |
Kernel Commands | 中文描述 |
kbase | 查找内核虚拟基址。 |
kchecksec | 检查内核硬化配置选项。 |
kcmdline | 返回内核命令行(/proc/cmdline)。 |
kconfig | 输出内核配置(需要CONFIG_IKCONFIG)。 |
kversion | 输出内核版本(/proc/version)。 |
slab | 打印slab分配器的信息。 |
Integrations Commands | 中文描述 |
ai | 向GPT-3询问当前调试上下文的问题。 |
ghidra | 使用Ghidra反编译给定的函数。 |
j | 使用IDA的游标与GDB同步。 |
r2 [radare2] | 启动radare2。 |
r2pipe | 通过r2pipe执行状态radare2命令。 |
rop [ropgadget] | 使用Jon Salwan的ROPgadget工具输出ROP gadget。 |
ropper | 使用ropper进行ROP gadget搜索。 |
rz [rizin] | 启动rizin。 |
rzpipe | 通过rzpipe执行状态rizin命令。 |
save_ida | 保存ida数据库。 |
WinDbg Commands | 中文描述 |
bc | 清除指定索引的断点。 |
bd | 禁用指定索引的断点。 |
be | 启用指定索引的断点。 |
bl | 列出断点。 |
bp | 在指定地址设置断点。 |
da | 在指定地址处转储字符串。 |
db | 从指定地址开始转储N字节。 |
dc | 从指定地址开始进行十六进制转储。 |
dd | 从指定地址开始转储N双字。 |
dds [kd, dps, dqs] | 在指定地址处转储指针和符号。 |
dq | 从指定地址开始转储N四字。 |
ds | 在指定地址处转储字符串。 |
dw | 从指定地址开始转储N字。 |
eb | 在指定地址处写入十六进制字节。 |
ed | 在指定地址处写入十六进制双字。 |
eq | 在指定地址处写入十六进制四字。 |
ew | 在指定地址处写入十六进制字。 |
eza | 在指定地址处写入字符串。 |
go | 'continue'命令的Windbg兼容别名。 |
k | 打印回溯(别名'bt')。 |
ln | 列出给定值附近的符号。 |
pc | 'nextcall'命令的Windbg兼容别名。 |
命令别名 | 中文描述 |
---|---|
peb | 不是Windows命令。 |
pwndbg Commands | 中文描述 |
---------- | ---------- |
pwndbg | 打印所有pwndbg命令的列表。 |
reinit_pwndbg | 使pwndbg重新初始化所有状态。 |
reload | 重新加载pwndbg。 |
theme | 显示pwndbg特有的主题配置。 |
themefile | 生成当前pwndbg主题选项的配置文件。 |
version | 显示GDB、Python和pwndbg的版本。 |
Developer Commands | 中文描述 |
dev_dump_instruction | 转储内部PwndbgInstruction属性。 |
Pwngdb:
以下是根据您提供的信息整理的表格,并包含了英文注释:
命令别名 | 中文描述 | 备注 |
---|---|---|
libc | 打印libc的基址 | |
ld | 打印ld的基址 | |
codebase | 打印代码段的基址 | |
heap | 打印堆的基址 | |
got | 打印全局偏移表信息 | |
dyn | 打印动态节信息 | |
findcall | 查找某些函数调用 | |
bcall | 在某些函数调用处设置断点 | |
tls | 打印线程本地存储地址 | |
at | 通过进程名称附加 | |
findsyscall | 查找系统调用 | |
fmtarg | 计算格式字符串的索引 | |
force | 计算在force房间的nb | |
heapinfo | 打印堆的一些信息 | heapinfo (Address of arena): 默认是当前线程的arena; 如果启用了tcache,它将显示缓存条目的信息 |
heapinfoall | 打印堆的所有信息 (所有线程) | |
arenainfo | 打印所有arena的信息 | |
chunkinfo | 打印chunk的信息 | chunkinfo (Address of victim): 打印受害chunkd的信息 |
chunkptr | 打印chunk的信息 | chunkptr (Address of user ptr): 打印用户指针的chunk信息 |
mergeinfo | 打印merge的信息 | mergeinfo (Address of victim): 打印受害地址的merge信息 |
printfastbin | 打印fastbin的一些信息 | |
tracemalloc on | 跟踪malloc和free,检测错误 | tracemalloc on: 需要先运行进程,然后开启tracemalloc; 您可以在pwngdb.py中设置DEBUG,然后它将打印所有malloc和空闲信息,例如屏幕截图。 |
parseheap | 解析堆布局 | |
magic | 打印glibc中的有用变量和函数 | |
fp | 显示FILE结构 | fp (Address of FILE): 显示FILE结构的地址 |
fpchain | 显示FILE的链表 | |
orange | 在_IO_flush_lockp中测试house of orange条件 | orange (Address of FILE): 测试FILE的house of orange条件; (glibc version <= 2.23)仅在glibc版本小于等于2.23时有效 |
(三)LibcSearcher:
git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
python setup.py develop
from LibcSearcher import *
# 第二个参数,为已泄露的实际地址, 或最后12位(例如:d90),int类型
obj = LibcSearcher("fgets", 0X7ff39014bd90)
obj.dump("system") # 输出 system 函数的偏移
obj.dump("str_bin_sh") # 输出 /bin/sh 的偏移
obj.dump("__libc_start_main_ret")
一些注意事项,在较高版本的python中会提示你使用虚拟环境。
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)