J'ai écrit ce programme simple en C pour expliquer un problème plus difficile avec les mêmes caractéristiques.
#include <stdio.h> int main(int argc, char *argv[]) { int n; while (1){ scanf("%d", &n); printf("%d\n", n); } return 0; }
Cela fonctionne comme prévu.
J'ai également écrit un script de sous-processus pour interagir avec le programme :
from subprocess import popen, pipe, stdout process = popen("./a.out", stdin=pipe, stdout=pipe, stderr=stdout) # sending a byte process.stdin.write(b'3') process.stdin.flush() # reading the echo of the number print(process.stdout.readline()) process.stdin.close()
Le problème est que si j'exécute le script python, l'exécution se bloque readline()
. En fait, si j'interromps le script, j'obtiens :
/tmp » python script.py ^ctraceback (most recent call last): file "/tmp/script.py", line 10, in <module> print(process.stdout.readline()) ^^^^^^^^^^^^^^^^^^^^^^^^^ keyboardinterrupt
Si je change mon script python :
from subprocess import popen, pipe, stdout process = popen("./a.out", stdin=pipe, stdout=pipe, stderr=stdout) with process.stdin as pipe: pipe.write(b"3") pipe.flush() # reading the echo of the number print(process.stdout.readline()) # sending another num: pipe.write(b"4") pipe.flush() process.stdin.close()
J'ai obtenu ce résultat :
» python script.py b'3\n' Traceback (most recent call last): File "/tmp/script.py", line 13, in <module> pipe.write(b"4") ValueError: write to closed file
Cela signifie que la première entrée a été envoyée correctement et que la lecture est terminée.
Je ne trouve vraiment rien pour expliquer ce comportement ; quelqu'un peut-il m'aider à comprendre ? Merci d'avance
[EDIT] : Comme il y a beaucoup de points qui nécessitent des éclaircissements, j'ai ajouté cette modification. Je me forme aux exploits de dépassement de tampon en utilisant la technique rop
et j'écris un script python pour y parvenir. Afin d'exploiter cette vulnérabilité, je dois découvrir l'adresse libc
et faire redémarrer le programme sans s'arrêter à cause d'aslr. Étant donné que le script sera exécuté sur la machine cible et que je ne sais pas quelles bibliothèques sont disponibles, j'utiliserai le sous-processus puisqu'il est intégré à Python. Sans entrer dans les détails, l'attaque envoie une séquence de rop
技术进行缓冲区溢出漏洞利用的培训,并且我正在编写一个 python 脚本来实现这一目标。为了利用这个漏洞,由于aslr,我需要发现libc
地址并使程序重新启动而不终止。由于脚本将在目标机器上执行,我不知道哪些库可用,那么我将使用 subprocess,因为它是内置于 python 中的。不详细说明,攻击在第一个 scanf
上发送一系列字节,目的是泄漏 libc
bytes
scanf
dans le but de divulguer l'adresse de base libc
et de redémarrer le programme puis elle envoie un ; deuxième Load valide pour obtenir un shell à travers lequel je communiquerai en mode interactif. Voici pourquoi :
n
Je dois envoyer des octets et je ne peux pas ajouter la fin stdin
Je dois garder .write(b'42n')
Envoyer un délimiteur entre les nombres lus par le programme C. scanf(3) accepte n'importe quel octet non numérique comme délimiteur. Pour la mise en mémoire tampon la plus simple, envoyez un caractère de nouvelle ligne (par exemple
Cela a fonctionné pour moi :
#include <stdio.h> int main(int argc, char *argv[]) { int n; while (1){ scanf("%d", &n); printf("%d\n", n); fflush(stdout); /* i've added this line only. */ } return 0; }
import subprocess p = subprocess.popen( ('./a.out',), stdin=subprocess.pipe, stdout=subprocess.pipe) try: print('a'); p.stdin.write(b'42 '); p.stdin.flush() print('b'); print(repr(p.stdout.readline())); print('c'); p.stdin.write(b'43\n'); p.stdin.flush() print('d'); print(repr(p.stdout.readline())); finally: print('e'); print(p.kill())
n
) 写入终端时,输出会自动刷新。因此 printf("%dn", n);
最后会隐式执行 fflush(stdout);
La raison pour laquelle le programme c d'origine fonctionne correctement lorsqu'il est exécuté de manière interactive dans une fenêtre de terminal est qu'en c, lorsqu'un caractère de nouvelle ligne () est écrit dans le terminal, la sortie est automatiquement actualisée. Par conséquent, printf("%dn", n);
finira par exécuter fflush(stdout);
implicitement.
subprocess
从 python 运行时,原始 c 程序无法工作的原因是它将输出写入管道(而不是终端),并且没有自动刷新到管道。发生的情况是,python 程序正在等待字节,而 c 程序不会将这些字节写入管道,但它正在等待更多字节(在下一个 scanf
Lors de l'utilisation de
pty
Si la modification du programme c n'est pas possible, vous devez alors utiliser des terminaux au lieu de canaux pour communiquer entre les programmes c et python.
import os, pty, subprocess master_fd, slave_fd = pty.openpty() p = subprocess.popen( ('./a.out',), stdin=slave_fd, stdout=slave_fd, preexec_fn=lambda: os.close(master_fd)) try: os.close(slave_fd) master = os.fdopen(master_fd, 'rb+', buffering=0) print('a'); master.write(b'42\n'); master.flush() print('b'); print(repr(master.readline())); print('c'); master.write(b'43\n'); master.flush() print('d'); print(repr(master.readline())); finally: print('e'); print(p.kill())
import os, pty, subprocess, termios master_fd, slave_fd = pty.openpty() ts = termios.tcgetattr(master_fd) ts[3] &= ~(termios.ICANON | termios.ECHO) termios.tcsetattr(master_fd, termios.TCSANOW, ts) p = subprocess.Popen( ('./a.out',), stdin=slave_fd, stdout=slave_fd, preexec_fn=lambda: os.close(master_fd)) try: os.close(slave_fd) master = os.fdopen(master_fd, 'rb+', buffering=0) print('A'); master.write(b'42 '); master.flush() print('B'); print(repr(master.readline())); print('C'); master.write(b'43\t'); master.flush() print('D'); print(repr(master.readline())); finally: print('E'); print(p.kill())
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!