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
from pwn import*
# from LibcSearcher import*

context(os = "linux",arch = "amd64",log_level = "debug")
binary = "./ciscn_2019_es_1"

if args["REMOTE"]:
io = remote("127.0.0.1",8080)
else :
io = process(binary)

elf = ELF(binary)
libc = ELF(" /home/source/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc.so.6")

s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(str(delim),data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(str(delim), data)
r = lambda num :io.recv(num)
ru = lambda delims, droio=False :io.recvuntil(delims, droio)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b''))
uu64 = lambda data :u64(data.ljust(8,b''))
leak = lambda name,addr :log.success('{} is---->{:#x}'.format(name, addr))
l64 = lambda :u64(io.recvuntil("")[-6:].ljust(8,b""))
l32 = lambda :u32(io.recvuntil("�")[-4:].ljust(4,b""))

def bug():
gdb.attach(io)
pause()

将地址头修改为

1
echo 28 | sudo tee /proc/sys/vm/mmap_rnd_bits

格式化字符串漏洞—->pwntools集成

1
2
3
4
5
6
fmtstr_payload(offset, writes, numbwritten=0, write_size="byte")
# 总共四个参数:
# offset --> 偏移量
# writes --> {被覆盖的地址:要写入的地址} 地址都为int型,也就是不需要使用p32或者p64打包
# numbwritten --> 已经由printf函数写入的字节数,默认为0
# write_size --> 逐byte/short/int写入,默认是byte,这样发送的字节少

关闭PIE

1
sudo sysctl -w kernel.randomize_va_space=0

gcc 在lunix下的编译命令参数

基础编译命令模板

1
2
3
4
5
6
7
8
gcc <输入文件.c> -o <输出文件名> \
-fno-stack-protector \ # 禁用栈保护(Stack Canary)
-no-pie \ # 禁用PIE(地址随机化)
-z execstack \ # 允许栈执行(禁用NX保护)
# 可选附加参数
-m32 \ # 编译为32位程序(需安装gcc-multilib)
-g \ # 包含调试信息
-O0 # 禁用优化

参数详解

  1. -fno-stack-protector
    • 关闭栈溢出保护(禁用Stack Canary),允许利用栈溢出漏洞。
  2. -no-pie
    • 禁用PIE(Position Independent Executable),确保代码段地址固定,方便计算偏移。
  3. -z execstack
    • 允许栈内存可执行(禁用NX保护),使注入到栈中的Shellcode可被执行。
  4. -m32(可选)
    • 编译32位程序(需先安装32位库:sudo apt install gcc-multilib)。
  5. -g(可选)
    • 保留调试信息,便于使用GDB分析程序。
  6. -O0(可选)
    • 禁用编译器优化,保持代码结构与源码一致。

完整示例

1
2
3
4
5
# 编译32位漏洞程序(禁用所有保护)
gcc vuln.c -o vuln -fno-stack-protector -no-pie -z execstack -m32 -g

# 编译64位漏洞程序(禁用保护)
gcc vuln.c -o vuln -fno-stack-protector -no-pie -z execstack -g

其他注意事项

  • 安装依赖
    若编译32位程序报错,需安装multilib支持:

    1
    sudo apt update && sudo apt install gcc-multilib
  • 动态链接 vs 静态链接
    默认动态链接(依赖系统库),若需静态编译可添加 -static,但文件体积会增大:

    1
    gcc vuln.c -o vuln -static -m32

系统调用号

1
https://blog.csdn.net/qq_29343201/article/details/52209588

更换文件libc

查看文件绝对路径

1
readlink -f filename

更换ld文件

1
patchelf --set-interpreter 新的ld文件的路径 当前程序名

示例

1
2
3
4
5
ckx@DESKTOP-0UT7FG3:/mnt/d/下载垃圾回收中心/buu$ patchelf --set-interpreter /home/ckx/tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so de1ctf_2019_weapon
ckx@DESKTOP-0UT7FG3:/mnt/d/下载垃圾回收中心/buu$ ldd de1ctf_2019_weapon
linux-vdso.so.1 (0x00007fffd0bdf000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb8ce5d7000)
/home/ckx/tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so => /lib64/ld-linux-x86-64.so.2 (0x00007fb8cea75000)

更换libc文件

1
patchelf --replace-needed 原来第二行的==>前的libc名 新的libc文件的路径

示例

1

解决闹钟的方法

第一种方法是在命令行直接替换可执行程序文本中的alarm(),如下面代码所示:

1
sed -i s/alarm/isnan/g ./ProgrammName

第二种:

1
vim ./ProgrammName

打开后直接输入/alarm进行搜索 找到之后修改为isnan

伪随机数

1
2
3
4
5
6
7
from pwn import *
import ctypes
import time
libc=ctypes.CDLL('path/to/file') #动态链接库,也就是.so文件。
seed = libc.time(0) #撞库去跑相同的时间。
libc.srand(seed) #用时间做种子
password=libc.rand() #得到随机数。

重定向

在linux中,输入输出是按照”流”(stream)的形象方式描述的,这样方便描述和处理数据,其中,标准流存在三种情况,所以使用read读取flag(ORW的时候)read以3起手,因为0~2都被使用了

  • 标准输入 STDIN_FILENO 文件描述符:0 stdio流:stdin
  • 标准输出 STDPUT_FILENO 文件描述符:1 stdio流:stdout
  • 标准错误 STDERR_FILENO 文件描述符:2 stdio流:stderr
重定向符 作用
cmd > file 将cmd的标准输出重定向,覆盖到file ,一般我们可以用这种方式来将终端获取的数据保存在文件里面
cmd >> file 将cmd的标准输出重定向,追加到file ,一般我们可以用这种方式来将终端获取的数据保存在文件里面
cmd < file 将file作为cmd的标准输入
cmd<<tag 从标准输入中读取数据,直到遇到了tag
cmd<file1>file2 将file1作为cmd的标准输入并且将标准输出重定向到file2
cmd 2>file 将cmd的标准错误重定向并且覆盖file
cmd 2>>file 将cmd的标准错误重定向并且追加file
2>&1 将标准错误和标准输出合并

重定向其实就相当于合并,比如2>&1这个时候标准错误和标准输出具备相同的效果,即,标准输出和标准错误一体,两者效果都具备,并且是标准输出(1)具备这个效果,shell里面使用exec 而在c语言里面使用dup2这个函数

而在shell里面为啥需要exec呢?exec能够修改整个 shell 进程的文件描述符表,永久性地将文件描述符 1 指向文件描述符 0 的位置,使得后续命令都有效,但是如果只是ls 2>&1(重定向要和命令一起使用),这个时候只是这一个命令有效果,但是因为整体还是没有完成重定向,导致这次的重定向也会失败

exec的作用:

  • exec 命令 ;命令代替shell程序,命令退出,shell 退出;比如 exec ls

  • exec 文件重定向,可以将文件的重定向就看为是shell程序的文件重定向 比如 exec 5</dev/null;exec 5<&-