1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
/* TODO: act proper if interface is promisc (only reply to packets
send to local host */
#include <assert.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <malloc.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#define BLEN 16384
#define PORT 80
const char * raw_payload =
"HTTP/1.0 301 Not enough crypto to process request\r\n"
"Location: %s\r\n"
"Connection: close\r\n"
"\r\n"
"<html><body>bye bye</body></html>";
unsigned chksum(unsigned short *buf, int length) {
unsigned sum = 0;
for (; length > 1; length -= 2)
sum += *buf++;
return sum;
}
unsigned short ipchksum(struct iphdr *ip) {
unsigned sum = chksum((unsigned short *) ip, sizeof(struct iphdr));
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return ~sum;
}
unsigned short tcpchksum(struct iphdr *ip, struct tcphdr *tcp, int length) {
unsigned sum =
chksum((unsigned short*) &(ip->saddr), sizeof(ip->saddr)) +
chksum((unsigned short*) &(ip->daddr), sizeof(ip->daddr)) +
((length + ip->protocol) << 8) +
chksum((unsigned short*) tcp, length);
if (length % 2)
sum += *(((char*) tcp) + length - 1);
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return ~sum;
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s target-url\n", argv[0]);
return 1;
}
static unsigned ack_src;
/* prepare input buffer */
char *ibuf = malloc(BLEN);
assert(ibuf != NULL);
struct ethhdr *i_eth = (struct ethhdr*) ibuf;
struct iphdr *i_ip = (struct iphdr*) (i_eth + 1);
struct tcphdr *i_tcp = (struct tcphdr*) (i_ip + 1);
char *i_pld = (char*) (i_tcp + 1);
/* prepare output buffer */
const size_t os =
sizeof(struct ethhdr) +
sizeof(struct iphdr) +
sizeof(struct tcphdr) +
strlen(raw_payload) + strlen(argv[1]) - 1;
char *obuf = malloc(os);
assert(obuf != NULL);
struct ethhdr *o_eth = (struct ethhdr*) obuf;
struct iphdr *o_ip = (struct iphdr*) (o_eth + 1);
struct tcphdr *o_tcp = (struct tcphdr*) (o_ip + 1);
char *o_pld = (char*) (o_tcp + 1);
/* setup sock */
int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
assert(fd >= 0);
/* retrieve interface idx (for send()) */
int ifidx;
{
struct ifreq req;
const char *if_name = "eth0";
strcpy((char*) &(req.ifr_name), if_name);
assert(ioctl(fd, SIOCGIFINDEX, &req) >= 0);
ifidx = req.ifr_ifindex;
printf("device index of %s is %d\n", if_name, ifidx);
}
/* prefill static output */
o_eth->h_proto = htons(ETH_P_IP);
o_ip->ihl = 5;
o_ip->version = 4;
o_ip->tos = 0;
o_ip->id = 0;
o_ip->frag_off = 0;
o_ip->ttl = 255;
o_ip->protocol = 6;
o_tcp->source = htons(PORT);
o_tcp->res1 = 0;
o_tcp->doff = 5;
o_tcp->ack = 1;
o_tcp->rst = 0;
o_tcp->psh = 1;
o_tcp->urg = 0;
o_tcp->ece = 0;
o_tcp->cwr = 0;
o_tcp->urg_ptr = 0;
o_tcp->window = htons(4); /* first 4 byte are harmless (and we won't
ack them) */
snprintf(o_pld, strlen(raw_payload) + strlen(argv[1]) - 1, raw_payload, argv[1]);
struct sockaddr_ll sall;
sall.sll_family = AF_PACKET;
sall.sll_ifindex = ifidx;
sall.sll_halen = 6;
memcpy(&(sall.sll_addr), &(o_eth->h_dest), sall.sll_halen);
sall.sll_protocol = sall.sll_hatype = sall.sll_pkttype = 0;
/* read packets forever */
while (1) {
int is = recv(fd, ibuf, BLEN, 0);
if ((is >= sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr)) && // packet long enough?
(ntohs(i_eth->h_proto) == ETH_P_IP) && // ip protocol?
(i_ip->ihl == 5) && // no IP options
(i_ip->protocol == 6) && // tcp protocol?
(ntohs(i_tcp->dest) == PORT)) { // port 80?
int size = 0;
/* eth & IP are common for all responses */
memcpy(&(o_eth->h_dest), &(i_eth->h_source), ETH_ALEN);
memcpy(&(o_eth->h_source), &(i_eth->h_dest), ETH_ALEN);
o_ip->check = 0;
memcpy(&(o_ip->saddr), &(i_ip->daddr), sizeof(o_ip->saddr));
memcpy(&(o_ip->daddr), &(i_ip->saddr), sizeof(o_ip->daddr));
o_tcp->dest = i_tcp->source;
o_tcp->check = 0;
if (i_tcp->syn && !i_tcp->ack) { /* first packet of a handshake? */
printf("syn\n");
size = os - strlen(o_pld);
o_tcp->seq = i_tcp->seq;
o_tcp->ack_seq = htonl(ntohl(i_tcp->seq) + 1);
o_tcp->fin = 0; //1;
o_tcp->syn = 1;
}else if (i_tcp->ack) {
printf("ack\n");
size = os;
o_tcp->seq = htonl(ntohl(i_tcp->ack_seq));
o_tcp->ack_seq = htonl(ntohl(i_tcp->ack_seq));
o_tcp->fin = 1;
o_tcp->syn = 0;
}
if (size > 0) {
o_ip->tot_len = htons(size - sizeof(struct ethhdr));
o_ip->check = ipchksum(o_ip);
o_tcp->check = tcpchksum(o_ip, o_tcp, size - sizeof(struct ethhdr) - sizeof(struct iphdr));
assert(sendto(fd, o_eth, size, 0, (struct sockaddr*) &sall, sizeof(struct sockaddr_ll)) == size);
}
}
}
close(fd);
}
|