首页
社区
课程
招聘
[原创]一次简单的golang栈溢出
发表于: 2023-8-15 22:02 13092

[原创]一次简单的golang栈溢出

2023-8-15 22:02
13092

将附件拖入ida,根据字符串可判断为go语言编写的程序:

动态运行发现是编写的一个简易shell,并且需要一个Cert才能正常工作:

逆向golang程序时,ida反编译功能基本报废,最好的办法就是看汇编。golang中的函数调用约定和标准的函数调用约定有所区别:传参用到的寄存器依次是:AX,BX,CX,DI,SI,R8,R9,R10,R11。接下来开始逆向工作。

首先根据报错字符串"Cert Is A Must"定位到地址0x4C1FC0处的函数,此函数依次将报错字符串从rodata段取出放到.bss段中以供后续调用:

根据字符串"Cert Is A Must"的交叉引用可以找到解析输入的函数,地址为0x4C1900。该函数首先会判断全局变量qword_5D1128是否为0,如果为0就去比较[rax]是否为指向字符串"cert"的字符串指针,[rax+8]处是否为4,任意条件不满足就会触发"Cert Is A Must"的报错:

直接使用gdb进行动态调试,将断点打在此函数开头处,观察rax寄存器的值:

可以发现用户输入被空格分开了,并且使用指针+长度的结构进行储存,rax指向的就是这样一个结构的数组。对应的rbx是这个数组的长度。所以只要用户输入被空格分开后的第一部分为字符串"cert"即可绕过报错"Cert Is A Must":

紧接着的是报错"Missing parameter",继续分析汇编,如果用户输入的第一部分为"cert"即可来到loc_4C1A24:

这里会再次比较输入的第一部分的长度,如果长度大于3就执行右边的逻辑块,小于三九执行左边的逻辑块。"cert"长度为4,所以会进入右边,这时候程序会判断用户输入是"cert"还是"echo",如果为"cert",就会检查rbx的值是否为3,如果不是3就会触发报错"Missing parameter":

根据上文的分析,rbx就是输入被空格分割成的份数,所以输入格式应该为"cert xxx xxx"。继续分析汇编,如果rbx为3,程序就会去判断输入的第二部分长度是否为9,并且和字符串"nAcDsMicN"进行比对,如果不同就会触发报错"Internal Err0r":

相同会进入0x4C14A0处的cert的解析函数,并且将输入的第三部分和其长度作为参数:

解析函数首先会进行rc4处理,然后再进行base64处理再和字符串“JLIX8pbSvYZu/WaG”进行比较,如果相同就会输出成功提示,并将全局变量qword_5D1128赋值为1。动态调试即可提取出rc4的key,将字符串base64解码、异或rc4的key即可得出要输入的值。脚本如下:

得出输入第三部分为"S33UAga1n@#!",所以输入"cert nAcDsMicN S33UAga1n@#!"之后即可通过检查,将qword_5D1128赋值为1,再次进入0x4C1900处的函数是就会直接跳过cert的判断,之后即可正常进行交互:

简单分析汇编逻辑会发现只有ls、cat、whoami、cd、echo这几个命令,其中cd会调用chdir函数,ls会执行ls -al命令,whoami和cat是调用的print打印写死的东西而echo的处理函数中存在溢出,在0x4C1854附近:

rax为索引,格式为echo part1 part2 part3 part4 ....,每个part最多0x200,总共加起来最多0x400,echo处理函数会将各个part整合起来写在栈上,如果有“+”则跳过栈上对应的位置的数据。而rsp+0x68距离返回地址的距离只有0x200多,所以存在一个栈溢出漏洞,构造payload进行rop即可。

遇到golang逆向或者pwn直接放弃伪代码边看汇编边调试 -.-

from pwn import *
my=b'nihaonihaoni'
my_c=p64(0xdfb5dbb8c64ce819)+p32(0xce2bd261)
key=[0]*12
for i in range(12):
    key[i]=my[i]^my_c[i]
 
final_base64=b"JLIX8pbSvYZu/WaG"
#00000000  24 b2 17 f2 96 d2 bd 86 6e fd 66 86              |$².ò.Ò½.nýf.|
final=b'\x24\xb2\x17\xf2\x96\xd2\xbd\x86\x6e\xfd\x66\x86'
 
res=[0]*12
for i in range(12):
    res[i]=final[i]^key[i]
print(bytes(res))
 
#S33UAga1n@#!
#nAcDsMicN
#cert nAcDsMicN S33UAga1n@#!
from pwn import *
my=b'nihaonihaoni'
my_c=p64(0xdfb5dbb8c64ce819)+p32(0xce2bd261)
key=[0]*12
for i in range(12):
    key[i]=my[i]^my_c[i]
 
final_base64=b"JLIX8pbSvYZu/WaG"
#00000000  24 b2 17 f2 96 d2 bd 86 6e fd 66 86              |$².ò.Ò½.nýf.|
final=b'\x24\xb2\x17\xf2\x96\xd2\xbd\x86\x6e\xfd\x66\x86'
 
res=[0]*12

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
  • pwn (1.64MB,25次下载)
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 2787
活跃值: (30801)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-8-16 09:14
0
游客
登录 | 注册 方可回帖
返回
//