XCTF-pwn-hello_pwn
这几天在尝试入门,学习pwn
的知识点,这是我关于pwn
入门做的第一道题目,学习pwn
需要很多的前置知识,并且需要一些环境,这里大概描述一下需要什么
- 拥有
C语言
基础 - 看懂简单的汇编代码
- 拥有一些
python
基础,需要使用到pwntools
- 拥有
linux
的基础,能够正常使用linux
终端 - 简单熟悉
ida
拥有上面的基础后,还需要一些pwn
的环境:
python
环境ida free
或者ida pro
: 注意ida free
是免费的,不过在反汇编成C语言
代码的时候需要联网pwntools
安装- 安装
pwndbg
linux
基础命令的使用gcc、checksec
对上述简单的了解以后,就可以进行简单的pwn
题目了,在网上搜课的时候,大多数的师傅都说pwn
的漏洞并不是很多,但是需要深入了解,入门难的原因时前置的知识要求高,虽然写这篇博客的时候,我也不太清楚为什么这个题目应该这样做,但是照着题目一点一点的做,不会的在网上搜,一点一点的就会变强,加油!
进入正题,首先我们启动靶机环境,然后题目给我们也提供了一个附件
可以下载,这就是靶机端口上运行的服务
我们首先需要下载提供的附件,然后对该附件进行分析,最后得到想要的flag
下载后先使用mv
命令将文件改名
然后使用file
查看文件属性
上述中重要的信息有:
- 该文件是一个
64
架构的ELF
可执行文件 - 该文件使用的库文件是
动态链接(dynamically linked)
接着使用checksec
命令查看该文件的安全保护机制,在最新版中需要使用--file=
指定文件名,可以使用--help
查看呢
这些安全机制还没有搞明白,慢慢学,但是比葫芦画瓢要知道这个步骤很重要
接着尝试运行一下该文件,手动的尝试分析,或者说感觉一下这个软件的功能
注意:有些时候在网上下载的ELF 可执行文件
是没有执行权限了,使用ls -l
可以看到文件是否有可执行(x)
的权限,如果没有,使用chmod +x 文件名
可以给该文件执行的权限
通过上述的分析,我们该程序进入的时候会输出~~ welcome to ctf ~~
和lets get helloworld for bof
一段内容,这些不重要,重要的是该程序接受了我们用户的输入,一般程序出问题,都是对用于的输入没有进行严格的过滤和限制,导致程序出现漏洞或者bug
,所以这里输出就是我们需要研究的地方
有了上述思路,使用ida free
将flag
文件打开,由于第一次,这里详细记录一下打开过程
上述图中有三个选项:
New
就是打开一个新的程序分析Go
就是打开之前已经分析过的程序分析- 第三个还没学,暂时不了解
我们选择New
然后调转到下面的页面
这是我们只需选择一个文件即可,这里选择flag
文件,Open
然后会进入该页面
我们知道,有很多类型的可执行文件,例如windows
中的exe、dll
,这里就是选择可执行程序的类型,一般情况下,ida
会自动分析程序的类型进行自动选择,这里我们可以不改变,点击OK
即可
现在已经在分析flag
程序了
该页面就是一个软件最基本的样式,占用页面最多的最多的就是汇编代码
区域,这些都是ida
分析该软件的特征模拟出的程序伪代码
。在左侧显示该程序中执行代码,调用函数的基本流程。
摁下f5
,ida
会将汇编代码转换为C语言代码
上述,在C语言
基础中,我们知道程序运行所有的内容主要在main
函数中,所以这里我们找到main
函数查看该程序的运行逻辑
{
alarm(0x3Cu);
setbuf(stdout, 0LL);
puts("~~ welcome to ctf ~~ ");
puts("lets get helloworld for bof");
read(0, &unk_601068, 0x10uLL);
if ( dword_60106C == 1853186401 )
sub_400686();
return 0LL;
}
上述中C语言
的read()
函数常用于读取文件描述符
中的内容,常用的三个参数read(文件描述符,指针地址,大小)
,那么上述代码中0
代表读取标准输入的值,也就是键盘输出
的值,将输出的之复制给unk_601068
这个变量的指针中,输入的内容大小最大为0x10uLL
也就是十六进制16
个字节uLL
代表数据类型为无符号的长长整形
在下方进行了一个if
语句的判断,如果dword_60106C
变量的之和1853186401
相等,那么执行sub_400686()
函数,我们双击sub_400686()
函数查看该函数的内容。
该函数会字节输出flag.txt
的内容,这里我们知道,unk_601068
是我们可以控制的,我们双击unk_601068
该变量在内存中的地址
出上图中可以看出,unk_601068
和dword_60106C
之差了四行,也就是四个字节
,也可以使用计算器手动计算
这里一共可以获取我们输入的字节数为16
个,所以这里可以利用read()
溢出,
- 输出四个无用值占位,然后输出
1853186401
就可以替换dword_60106C
变量的值, - 在
if
调用dword_60106C
变量时调用的是该变量的内存地址,也就是0x60106C
, - 然而这个内存地址的值已经被我们
unk_601068
变量的值通过read()
函数溢出更改为1853186401
, - 最后该程序判断
dword_60106C
的值等于1853186401
,输出flag
所以我们得思路就是连接靶机运行该脚本,然后输入四个aaaa
,然后输入1853186401
就对了
但是遗憾是,并没有获得flag
,这里我们需要使用pwntools
中的p32()
函数获取我们传入的字符
可以看到为aaun
,再次连接靶机,输入aaaaaaun
即可获得flag
这里有一个疑问还有没有解决,为什么手动输入1853186401
不行,虽然大概知为什么是错的,但是没有得到证实,不清楚其原理,这让我很难受。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程