# 题目分析

    Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      PIE enabled

1. go: 选择一个level，然后会再问你一次level，输入之后，回答两次level想加这么多次的问题，就是a * b类型，回答完成之后输出你在多少秒内完成了多少level
2. hint: 打印NO PWN NO FUN
3. give up: 退出

## go

int go(void)
{
int v1; // ST0C_4@10
__int64 v2; // [sp+0h] [bp-120h]@1
int v3; // [sp+8h] [bp-118h]@9
__int64 v4; // [sp+10h] [bp-110h]@0
__int64 v5; // [sp+10h] [bp-110h]@4
signed __int64 v6; // [sp+18h] [bp-108h]@7
__int64 v7; // [sp+20h] [bp-100h]@10

puts("How many levels?");
if ( v2 > 0 )
v4 = v2;
else
puts("Coward");
puts("Any more?");
if ( v5 > 0 )
{
if ( v5 <= 999 )
{
v6 = v5;
}
else
{
puts("More levels than before!");
v6 = 1000LL;
}
puts("Let's go!'");
v3 = time(0LL);
if ( (unsigned int)level(v6) != 0 )
{
v1 = time(0LL);
sprintf((char *)&v7, "Great job! You finished %d levels in %d seconds\n", v6, (unsigned int)(v1 - v3));
puts((const char *)&v7);
}
else
{
puts("You failed.");
}
exit(0);
}
return puts("Coward");
}

__int64 __fastcall level(signed int a1)
{
__int64 result; // rax@2
__int64 inputs; // rax@8
char buf[32]; // [sp+10h] [bp-30h]@1
int num2; // [sp+34h] [bp-Ch]@5
int num1; // [sp+38h] [bp-8h]@5
int i; // [sp+3Ch] [bp-4h]@5

*(_QWORD *)buf = 0LL;
*(_QWORD *)&buf[8] = 0LL;
*(_QWORD *)&buf[16] = 0LL;
*(_QWORD *)&buf[24] = 0LL;
if ( a1 )
{
if ( (unsigned int)level(a1 - 1) == 0 )
{
result = 0LL;
}
else
{
num1 = rand() % a1;
num2 = rand() % a1;
puts("====================================================");
printf("Level %d\n", (unsigned int)a1);
printf("Question: %d * %d = ? Answer:", (unsigned int)num1, (unsigned int)num2);
for ( i = read(0, buf, 0x400uLL); i & 7; ++i )
buf[i] = 0;
inputs = strtol(buf, 0LL, 10);
}
}
else
{
result = 1LL;
}
return result;
}

## hint

int hint(void)
{
signed __int64 v1; // [sp+8h] [bp-108h]@2
signed int v2; // [sp+10h] [bp-100h]@3
signed __int16 v3; // [sp+14h] [bp-FCh]@3

if ( show_hint )
{
sprintf((char *)&v1, "Hint: %p\n", &system, &system);
}
else
{
v1 = 0x4E204E5750204F4ELL;
v2 = 0x5546204F;
v3 = 0x4E;
}
return puts((const char *)&v1);
}

show_hint变量位于BSS，由于开启了PIE，是没法拿到地址的。 这里有个问题，只看C函数是看不出来的，我们来看汇编：

var_110         = qword ptr -110h
.text:0000000000000CF0
.text:0000000000000CF0                 push    rbp
.text:0000000000000CF1                 mov     rbp, rsp
.text:0000000000000CF4                 sub     rsp, 110h
.text:0000000000000CFB ; 8:     sprintf((char *)&v1, "Hint: %p\n", &system, &system);
.text:0000000000000CFB                 mov     rax, cs:system_ptr
.text:0000000000000D02                 mov     [rbp+var_110], rax
.text:0000000000000D09 ; 6:   if ( show_hint )
.text:0000000000000D09                 lea     rax, show_hint
.text:0000000000000D10                 mov     eax, [rax]
.text:0000000000000D12                 test    eax, eax
.text:0000000000000D14                 jz      short loc_D41
.text:0000000000000D16                 mov     rax, [rbp+var_110]
.text:0000000000000D1D                 lea     rdx, [rbp+var_110]
.text:0000000000000D24                 lea     rcx, [rdx+8]
.text:0000000000000D28                 mov     rdx, rax
.text:0000000000000D2B                 lea     rsi, aHintP     ; "Hint: %p\n"
.text:0000000000000D32                 mov     rdi, rcx        ; s
.text:0000000000000D35                 mov     eax, 0
.text:0000000000000D3A                 call    _sprintf
.text:0000000000000D3F                 jmp     short loc_D66

# 漏洞分析

1. go函数中的两次level询问，第一次如果小于等于0会导致本应该记录第一次询问的level结果的变量未初始化，第二次询问没有判断是否小于0
2. level函数存在栈溢出
3. hint函数始终会将system的值放在栈上

# 利用思路

1. 使用hint，将system放在栈上
2. 进入go，第一次给出小于等于0的值，使得v4=system的地址。
4. 完成999次回答
6. 触发，搞定

# 总结

## 关于vsyscall

vsyscall是以前linux内核使用的用来处理syscall的一个解决方案，后来被废弃，由vdso方案代替，但是这个方案由于历史原因保留了下来。

vsyscall的特点是在于其地址是固定的，所以可以用来在PIE+ASLR的情况中进行一定的利用。不过他的利用也有一些限制，vsyscall有一些固定的entry入口，内核在处理的时候会判断一下，如果执行的部分在vsyscall内，但是不是从entry入口开始的，会直接seg fault掉。

08-11 86

07-06 4177

09-16 179

11-23 164

09-08 32

05-01 111

11-02

10-08 2375

04-30 137

07-13 1万+

08-31 28

10-10 1002

03-25 176

07-27

03-12 928

03-13 7560

04-03 3万+

10-13

04-23 1596

06-30 1137

01-19 1万+

05-09 1896

04-21 1078

11-22 312

12-01 1162

06-17

07-14 556

03-24 1329

07-23 606

05-07 8115

11-21 1236

04-22 859

06-01 1003

10-26 5310

03-13 723

07-10 5150

08-10 530

09-08 1380

12-26 2万+

03-04 1500

03-20 6642

04-14 1488

04-21 2821

05-07 1万+

05-08 5704

06-17 5705

07-04 1478

10-25 453

11-09 407

03-24 658

03-19 81万+

04-14 58万+

03-13 14万+

03-01 13万+

03-04 13万+

03-05 5216

03-05 5万+

03-08 4万+

03-08 7万+

03-10 12万+

03-10 18万+

03-12 10万+

03-13 11万+

03-16 10万+

03-18 8153

03-19 8万+

03-20 6917

03-22 4万+

03-24 3万+

03-25 3万+

05-08 4万+

03-25 8万+

03-26 1万+

03-27 4万+

03-29 21万+

03-29 9万+

03-30 15万+

05-28 4780

05-28 1万+

04-01 6673

#### 一文带你入门Java Stream流，太强了

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客