Arch: amd64-64-little<br>
RELRO: Partial RELRO<br>
Stack: No canary found<br>
NX: NX enabled<br>
PIE: PIE enabled<br>
以下是main函数初始化完后的栈构造
除了Canary之外的保护都开了,由于开启了PIE无法直接获悉具体指令地址,所以无法直接构建ROP<br>
system
调用位于main函数中低2字节为0x0AD2
处
位于RBP-0x18
处是main函数地址<br>
位于RSP+0x10
处是VDSO基址
或在GDB中 vmmap<br>
0xffffffffff600000 0xffffffffff601000 --xp 1000 0 [vsyscall]
或cat /proc/1/maps | grep vsyscal<br>
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
对于这个实现方法,成功在本地打通并且getShell,但是在远程却并不适用,题目名叫做Ret2VDSO,直接使用Vsyscall我也觉得应该不是出题人本意,但是我并没有完全理解VDSO和该程序的利用,也没有找到相关类似题目的WP,根据我对vsyscall
和vdso
的理解推测或许是靶机上压根就没有vsyscall,所以对于栈溢出的利用仅到此为止;
我曾尝试爆破VDSO基址,并加上0x5FC
作为偏移来作为RetGadGet
,但是这个方法不论是在远程还是本地都没成功,原因是在x64下,该地址有3个字节也既12位是随机的,不同于x32下仅有1字节,爆破概率是1/256;在本程序中爆破概率低达1/16777216,在绞尽脑汁想不出如何通过栈溢出来打通该程序时,确实抱着侥幸尝试过爆破VDSO基址,但不论本地还是远程最终都没能打通,即使打通了本地,也许我找的VDSO文件的ret偏移0x5FC
在远程上也并不适用,所以我最终放弃了
根据分析可知以下三点
由于程序中的seed根据time()来生成,所以这是可以被预估的,只需要提前预估未来的某一个符合rand结果小于9位数用户可输入的时间戳并且等时间到时发送内容即可
我对该机制的理解还是过于浅显,以至于无法用出题人希望的方式解出这道题,目 前这题作为遗留问题,在我理解深入后再回过头来思考这题的解法
find / -name '*vdso*.so*'
int
getint()
{
/
/
buf大小为
16
字节
char buf[
16
];
/
/
[rsp
+
0h
] [rbp
-
10h
]
/
/
仅允许用户输入
8
个字节
read(
0
, buf,
8uLL
);
return
atoi(buf);
/
/
将输入转为数字并返回
}
int
menu()
{
puts(
"------welcome------"
);
puts(
"1.get gift"
);
puts(
"2.overflow"
);
puts(
"3.exit"
);
puts(
"[+]give me your choice:"
);
return
getint();
}
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
unsigned
int
seed;
/
/
eax
int
inputNum;
/
/
ebx
char buf[
56
];
/
/
[rsp
+
0h
] [rbp
-
50h
] BYREF
int
choice;
/
/
[rsp
+
38h
] [rbp
-
18h
]
int
counter;
/
/
[rsp
+
3Ch
] [rbp
-
14h
]
setvbuf(_bss_start,
0LL
,
2
,
0LL
);
setvbuf(stdin,
0LL
,
1
,
0LL
);
counter
=
2
;
do
{
if
( !counter )
/
/
如果counter为
0
则结束循环
break
;
choice
=
menu();
/
/
获取用户输入
if
( choice
=
=
1
)
{
-
-
counter;
puts(
"input num:"
);
seed
=
time(
0LL
);
/
/
将当前时间戳作为seed【不安全的引用】
srand(seed);
inputNum
=
getint();
/
/
获取用户输入【注意是先获取seed后才等待输入】
if
( inputNum
=
=
rand() )
/
/
对比输入和rand结果,如果一致则直接getshell
system(
"/bin/sh"
);
}
if
( choice
=
=
2
)
{
-
-
counter;
puts(
"hello from ctfhub"
);
read(
0
, buf,
0xD0uLL
);
/
/
【栈溢出】
}
}
while
( choice !
=
3
);
/
/
即使输入
3
也会再跑一次循环【逻辑错误】
return
0
;
}
int
getint()
{
/
/
buf大小为
16
字节
char buf[
16
];
/
/
[rsp
+
0h
] [rbp
-
10h
]
/
/
仅允许用户输入
8
个字节
read(
0
, buf,
8uLL
);
return
atoi(buf);
/
/
将输入转为数字并返回
}
int
menu()
{
puts(
"------welcome------"
);
puts(
"1.get gift"
);
puts(
"2.overflow"
);
puts(
"3.exit"
);
puts(
"[+]give me your choice:"
);
return
getint();
}
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
unsigned
int
seed;
/
/
eax
int
inputNum;
/
/
ebx
char buf[
56
];
/
/
[rsp
+
0h
] [rbp
-
50h
] BYREF
int
choice;
/
/
[rsp
+
38h
] [rbp
-
18h
]
int
counter;
/
/
[rsp
+
3Ch
] [rbp
-
14h
]
setvbuf(_bss_start,
0LL
,
2
,
0LL
);
setvbuf(stdin,
0LL
,
1
,
0LL
);
counter
=
2
;
do
{
if
( !counter )
/
/
如果counter为
0
则结束循环
break
;
choice
=
menu();
/
/
获取用户输入
if
( choice
=
=
1
)
{
-
-
counter;
puts(
"input num:"
);
seed
=
time(
0LL
);
/
/
将当前时间戳作为seed【不安全的引用】
srand(seed);
inputNum
=
getint();
/
/
获取用户输入【注意是先获取seed后才等待输入】
if
( inputNum
=
=
rand() )
/
/
对比输入和rand结果,如果一致则直接getshell
system(
"/bin/sh"
);
}
if
( choice
=
=
2
)
{
-
-
counter;
puts(
"hello from ctfhub"
);
read(
0
, buf,
0xD0uLL
);
/
/
【栈溢出】
}
}
while
( choice !
=
3
);
/
/
即使输入
3
也会再跑一次循环【逻辑错误】
return
0
;
}
.text:
0000000000000A38
;
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
.text:
0000000000000A38
public main
.text:
0000000000000A38
main proc near ; DATA XREF: _start
+
1D
↑o
.text:
0000000000000A38
.text:
0000000000000A38
buf
=
byte ptr
-
50h
.text:
0000000000000A38
choice
=
dword ptr
-
18h
.text:
0000000000000A38
counter
=
dword ptr
-
14h
.text:
0000000000000A38
.text:
0000000000000A38
; __unwind {
.text:
0000000000000A38
push rbp
.text:
0000000000000A39
mov rbp, rsp
.text:
0000000000000A3C
push rbx
.text:
0000000000000A3D
sub rsp,
48h
.text:
0000000000000A41
;
8
: setvbuf(_bss_start,
0LL
,
2
,
0LL
);
.text:
0000000000000A41
mov rax, cs:__bss_start
.text:
0000000000000A48
mov ecx,
0
; n
.text:
0000000000000A4D
mov edx,
2
; modes
.text:
0000000000000A52
mov esi,
0
; buf
.text:
0000000000000A57
mov rdi, rax ; stream
.text:
0000000000000A5A
call _setvbuf
.text:
0000000000000A5A
.text:
0000000000000A5F
;
9
: setvbuf(stdin,
0LL
,
1
,
0LL
);
.text:
0000000000000A5F
mov rax, cs:stdin@@GLIBC_2_2_5
.text:
0000000000000A66
mov ecx,
0
; n
.text:
0000000000000A6B
mov edx,
1
; modes
.text:
0000000000000A70
mov esi,
0
; buf
.text:
0000000000000A75
mov rdi, rax ; stream
.text:
0000000000000A78
call _setvbuf
.text:
0000000000000A78
.text:
0000000000000A7D
;
10
: v8
=
2
;
.text:
0000000000000A7D
mov [rbp
+
counter],
2
.text:
0000000000000A84
jmp loc_B10
.text:
0000000000000A84
.text:
0000000000000A89
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.text:
0000000000000A89
;
15
: choice
=
getInput();
.text:
0000000000000A89
.text:
0000000000000A89
loc_A89: ; CODE XREF: main
+
DC↓j
.text:
0000000000000A89
mov eax,
0
.text:
0000000000000A8E
call printMenu ; 打印菜单并获取用户输入数字
.text:
0000000000000A8E
;
1
:getGift,判断用户输入和随机数是否相同
.text:
0000000000000A8E
;
2
:overflow,栈溢出
.text:
0000000000000A8E
;
3
:结束
.text:
0000000000000A8E
.text:
0000000000000A93
mov [rbp
+
choice], eax
.text:
0000000000000A96
;
16
:
if
( choice
=
=
1
)
.text:
0000000000000A96
cmp
[rbp
+
choice],
1
.text:
0000000000000A9A
jnz short loc_ADE
.text:
0000000000000A9A
.text:
0000000000000A9C
;
18
:
-
-
v8;
.text:
0000000000000A9C
sub [rbp
+
counter],
1
; ↓↓↓↓↓↓↓↓↓↓用户输入为
1
,getGift↓↓↓↓↓↓↓↓↓↓
.text:
0000000000000AA0
;
19
: puts(
"input num:"
);
.text:
0000000000000AA0
lea rdi, aInputNum ;
"input num:"
.text:
0000000000000AA7
call _puts
.text:
0000000000000AA7
.text:
0000000000000AAC
;
20
: seed
=
time(
0LL
);
.text:
0000000000000AAC
mov edi,
0
; timer
.text:
0000000000000AB1
call _time
.text:
0000000000000AB1
.text:
0000000000000AB6
;
21
: srand(seed);
.text:
0000000000000AB6
mov edi, eax ; seed
.text:
0000000000000AB8
call _srand
.text:
0000000000000AB8
.text:
0000000000000ABD
;
22
: inputNum
=
getInputNumber();
.text:
0000000000000ABD
mov eax,
0
.text:
0000000000000AC2
call getInputNumber
.text:
0000000000000AC2
.text:
0000000000000AC7
mov ebx, eax
.text:
0000000000000AC9
;
23
:
if
( inputNum
=
=
rand() )
.text:
0000000000000AC9
call _rand
.text:
0000000000000AC9
.text:
0000000000000ACE
cmp
ebx, eax
.text:
0000000000000AD0
jnz short loc_ADE
.text:
0000000000000AD0
.text:
0000000000000AD2
;system(
"/bin/sh"
);getShell代码位于mainAD2处
.text:
0000000000000AD2
lea rdi, command ;
"/bin/sh"
.text:
0000000000000AD9
call _system
; ↑↑↑↑↑↑↑↑↑↑↑用户输入为
1
:getGift↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:
0000000000000AD9
.text:
0000000000000ADE
;
26
:
if
( choice
=
=
2
)
.text:
0000000000000ADE
.text:
0000000000000ADE
loc_ADE: ; CODE XREF: main
+
62
↑j
.text:
0000000000000ADE
; main
+
98
↑j
.text:
0000000000000ADE
cmp
[rbp
+
choice],
2
.text:
0000000000000AE2
jnz short loc_B0A
; ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓用户输入为
2
:overflow↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
.text:
0000000000000AE2
.text:
0000000000000AE4
;
28
:
-
-
v8;
.text:
0000000000000AE4
sub [rbp
+
counter],
1
.text:
0000000000000AE8
;
29
: puts(
"hello from ctfhub"
);
.text:
0000000000000AE80
lea rdi, aHelloFromCtfhu ;
"hello from ctfhub"
.text:
0000000000000AEF
call _puts
.text:
0000000000000AEF
.text:
0000000000000AF4
;
30
: read(
0
, buf,
0xD0uLL
);
.text:
0000000000000AF4
lea rax, [rbp
+
buf]
.text:
0000000000000AF8
mov edx,
0D0h
; nbytes
.text:
0000000000000AFD
mov rsi, rax ; buf
.text:
0000000000000B00
mov edi,
0
; fd
.text:
0000000000000B05
call _read
; ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑用户输入为
2
:overflow↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:
0000000000000B05
.text:
0000000000000B0A
;
33
:
while
( choice !
=
3
);
.text:
0000000000000B0A
.text:
0000000000000B0A
loc_B0A: ; CODE XREF: main
+
AA↑j
.text:
0000000000000B0A
cmp
[rbp
+
choice],
3
.text:
0000000000000B0E
jz short loc_B1C
.text:
0000000000000B0E
.text:
0000000000000B10
;
13
:
if
( !v8 )
.text:
0000000000000B10
.text:
0000000000000B10
loc_B10: ; CODE XREF: main
+
4C
↑j
.text:
0000000000000B10
cmp
[rbp
+
counter],
0
.text:
0000000000000B14
;
14
:
break
;
.text:
0000000000000B14
jnz loc_A89
.text:
0000000000000B14
.text:
0000000000000B1A
jmp short loc_B1D
.text:
0000000000000B1A
.text:
0000000000000B1C
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.text:
0000000000000B1C
.text:
0000000000000B1C
loc_B1C: ; CODE XREF: main
+
D6↑j
.text:
0000000000000B1C
nop
.text:
0000000000000B1C
.text:
0000000000000B1D
;
34
:
return
0
;
.text:
0000000000000B1D
.text:
0000000000000B1D
loc_B1D: ; CODE XREF: main
+
E2↑j
.text:
0000000000000B1D
mov eax,
0
.text:
0000000000000B22
add rsp,
48h
.text:
0000000000000B26
pop rbx
.text:
0000000000000B27
pop rbp
.text:
0000000000000B28
retn
.text:
0000000000000B28
; }
/
/
starts at A38
.text:
0000000000000B28
.text:
0000000000000B28
main endp
.text:
0000000000000A38
;
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
.text:
0000000000000A38
public main
.text:
0000000000000A38
main proc near ; DATA XREF: _start
+
1D
↑o
.text:
0000000000000A38
.text:
0000000000000A38
buf
=
byte ptr
-
50h
.text:
0000000000000A38
choice
=
dword ptr
-
18h
.text:
0000000000000A38
counter
=
dword ptr
-
14h
.text:
0000000000000A38
.text:
0000000000000A38
; __unwind {
.text:
0000000000000A38
push rbp
.text:
0000000000000A39
mov rbp, rsp
.text:
0000000000000A3C
push rbx
.text:
0000000000000A3D
sub rsp,
48h
.text:
0000000000000A41
;
8
: setvbuf(_bss_start,
0LL
,
2
,
0LL
);
.text:
0000000000000A41
mov rax, cs:__bss_start
.text:
0000000000000A48
mov ecx,
0
; n
.text:
0000000000000A4D
mov edx,
2
; modes
.text:
0000000000000A52
mov esi,
0
; buf
.text:
0000000000000A57
mov rdi, rax ; stream
.text:
0000000000000A5A
call _setvbuf
.text:
0000000000000A5A
.text:
0000000000000A5F
;
9
: setvbuf(stdin,
0LL
,
1
,
0LL
);
.text:
0000000000000A5F
mov rax, cs:stdin@@GLIBC_2_2_5
.text:
0000000000000A66
mov ecx,
0
; n
.text:
0000000000000A6B
mov edx,
1
; modes
.text:
0000000000000A70
mov esi,
0
; buf
.text:
0000000000000A75
mov rdi, rax ; stream
.text:
0000000000000A78
call _setvbuf
.text:
0000000000000A78
.text:
0000000000000A7D
;
10
: v8
=
2
;
.text:
0000000000000A7D
mov [rbp
+
counter],
2
.text:
0000000000000A84
jmp loc_B10
.text:
0000000000000A84
.text:
0000000000000A89
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.text:
0000000000000A89
;
15
: choice
=
getInput();
.text:
0000000000000A89
.text:
0000000000000A89
loc_A89: ; CODE XREF: main
+
DC↓j
.text:
0000000000000A89
mov eax,
0
.text:
0000000000000A8E
call printMenu ; 打印菜单并获取用户输入数字
.text:
0000000000000A8E
;
1
:getGift,判断用户输入和随机数是否相同
.text:
0000000000000A8E
;
2
:overflow,栈溢出
.text:
0000000000000A8E
;
3
:结束
.text:
0000000000000A8E
.text:
0000000000000A93
mov [rbp
+
choice], eax
.text:
0000000000000A96
;
16
:
if
( choice
=
=
1
)
.text:
0000000000000A96
cmp
[rbp
+
choice],
1
.text:
0000000000000A9A
jnz short loc_ADE
.text:
0000000000000A9A
.text:
0000000000000A9C
;
18
:
-
-
v8;
.text:
0000000000000A9C
sub [rbp
+
counter],
1
; ↓↓↓↓↓↓↓↓↓↓用户输入为
1
,getGift↓↓↓↓↓↓↓↓↓↓
.text:
0000000000000AA0
;
19
: puts(
"input num:"
);
.text:
0000000000000AA0
lea rdi, aInputNum ;
"input num:"
.text:
0000000000000AA7
call _puts
.text:
0000000000000AA7
.text:
0000000000000AAC
;
20
: seed
=
time(
0LL
);
.text:
0000000000000AAC
mov edi,
0
; timer
.text:
0000000000000AB1
call _time
.text:
0000000000000AB1
.text:
0000000000000AB6
;
21
: srand(seed);
.text:
0000000000000AB6
mov edi, eax ; seed
.text:
0000000000000AB8
call _srand
.text:
0000000000000AB8
.text:
0000000000000ABD
;
22
: inputNum
=
getInputNumber();
.text:
0000000000000ABD
mov eax,
0
.text:
0000000000000AC2
call getInputNumber
.text:
0000000000000AC2
.text:
0000000000000AC7
mov ebx, eax
.text:
0000000000000AC9
;
23
:
if
( inputNum
=
=
rand() )
.text:
0000000000000AC9
call _rand
.text:
0000000000000AC9
.text:
0000000000000ACE
cmp
ebx, eax
.text:
0000000000000AD0
jnz short loc_ADE
.text:
0000000000000AD0
.text:
0000000000000AD2
;system(
"/bin/sh"
);getShell代码位于mainAD2处
.text:
0000000000000AD2
lea rdi, command ;
"/bin/sh"
.text:
0000000000000AD9
call _system
; ↑↑↑↑↑↑↑↑↑↑↑用户输入为
1
:getGift↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:
0000000000000AD9
.text:
0000000000000ADE
;
26
:
if
( choice
=
=
2
)
.text:
0000000000000ADE
.text:
0000000000000ADE
loc_ADE: ; CODE XREF: main
+
62
↑j
.text:
0000000000000ADE
; main
+
98
↑j
.text:
0000000000000ADE
cmp
[rbp
+
choice],
2
.text:
0000000000000AE2
jnz short loc_B0A
; ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓用户输入为
2
:overflow↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
.text:
0000000000000AE2
.text:
0000000000000AE4
;
28
:
-
-
v8;
.text:
0000000000000AE4
sub [rbp
+
counter],
1
.text:
0000000000000AE8
;
29
: puts(
"hello from ctfhub"
);
.text:
0000000000000AE80
lea rdi, aHelloFromCtfhu ;
"hello from ctfhub"
.text:
0000000000000AEF
call _puts
.text:
0000000000000AEF
.text:
0000000000000AF4
;
30
: read(
0
, buf,
0xD0uLL
);
.text:
0000000000000AF4
lea rax, [rbp
+
buf]
.text:
0000000000000AF8
mov edx,
0D0h
; nbytes
.text:
0000000000000AFD
mov rsi, rax ; buf
.text:
0000000000000B00
mov edi,
0
; fd
.text:
0000000000000B05
call _read
; ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑用户输入为
2
:overflow↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:
0000000000000B05
.text:
0000000000000B0A
;
33
:
while
( choice !
=
3
);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2023-3-13 09:48
被LeaMov编辑
,原因: 上传样本,修改md格式