Maison > développement back-end > Tutoriel Python > Programmes et sous-processus C

Programmes et sous-processus C

WBOY
Libérer: 2024-02-22 13:01:18
avant
851 Les gens l'ont consulté

Programmes et sous-processus C

Contenu de la question

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;
}
Copier après la connexion

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()
Copier après la connexion

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
Copier après la connexion

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()
Copier après la connexion

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
Copier après la connexion

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 上发送一系列字节,目的是泄漏 libcbytes

sur le premier 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 :
  1. Je ne peux utiliser que les bibliothèques intégrées
  2. nJe dois envoyer des octets et je ne peux pas ajouter la fin
  3.  : ma charge utile ne s'alignera pas ou pourrait provoquer un échec
  4. stdinJe dois garder
  5. ouvert
  6. Je ne peux pas changer le code C


Bonne réponse

Modifiez-les :
  • .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

    ) depuis Python. Sans délimiteurs, scanf(3) attendra indéfiniment plus de chiffres.
  • Flush sortie après chaque écriture (en c et python).

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;
}
Copier après la connexion
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())
Copier après la connexion
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 程序不会将这些字节写入管道,但它正在等待更多字节(在下一个 scanfLors de l'utilisation de

), les deux programmes s'attendent donc indéfiniment. (Cependant, une actualisation automatique partielle se produira après la sortie de quelques kibs (généralement 8 192 octets). Mais un seul nombre décimal est trop court pour déclencher l'opération.)

ptySi 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.

Le module python peut créer des terminaux, qui ont fonctionné pour moi avec votre programme C d'origine :

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())
Copier après la connexion

Si vous ne souhaitez pas envoyer de nouvelles lignes depuis python, voici une solution sans nouvelles lignes, cela a fonctionné pour moi : 🎜
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())
Copier après la connexion

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!

source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal