1. #include "airodump.h"
  2. #include "ui_airodump.h"
  3. Airodump::Airodump(QWidget *parent) :
  4. QWidget(parent),
  5. ui(new Ui::Airodump)
  6. {
  7. ui->setupUi(this);
  8. process = new QProcess(this);
  9. //initializing
  10. //this->ui->pushButtonStop->hide();
  11. //connecting buttons
  12. connect(this->ui->pushButtonStart, SIGNAL(clicked()), this, SLOT(start()));
  13. connect(this->ui->pushButtonStop, SIGNAL(clicked()), this, SLOT(stop()));
  14. //connect button to sort
  15. connect(this->ui->pushButtonSort, SIGNAL(clicked()), this, SLOT(sort()));
  16. //connect things to trigger associated stations
  17. connect(this->ui->tableWidgetAirodumpGeneral, SIGNAL(itemSelectionChanged()), this, SLOT(selectStationsAssociated()));
  18. //below table, signal when new station appear
  19. connect(this, SIGNAL(stationAppear(infoConnectionBssid)), this, SLOT(newStationAppear(infoConnectionBssid)));
  20. //attack deauth
  21. connect(this->ui->pushButtonDeauth, SIGNAL(clicked()), this, SLOT(attackDeauth()));
  22. //attack auth
  23. connect(this->ui->pushButtonAuth, SIGNAL(clicked()), this, SLOT(attackAuth()));
  24. //attack broadcast
  25. connect(this->ui->pushButtonBroadcast, SIGNAL(clicked()), this, SLOT(attackBroadcast()));
  26. //aircrack
  27. connect(this->ui->pushButtonCrack, SIGNAL(clicked()), this, SLOT(aircrack()));
  28. //capture
  29. connect(this->ui->pushButtonCapture, SIGNAL(clicked()), this, SLOT(capture()));
  30. //status
  31. connect(this, SIGNAL(statusChanged(QString)), this->ui->lineEditStatus, SLOT(setText(QString)));
  32. connect(this, SIGNAL(statusChanged(QString)), this, SLOT(enableCorrectOptions(QString)));
  33. //time elapsed
  34. connect(&this->time, SIGNAL(timeout()), this, SLOT(uploadTime()));
  35. //not implemented
  36. connect(this->ui->pushButtonARP, SIGNAL(clicked()), this, SLOT(notImplemented()));
  37. connect(this->ui->pushButtonChop, SIGNAL(clicked()), this, SLOT(notImplemented()));
  38. connect(this->ui->pushButtonChop, SIGNAL(clicked()), this, SLOT(notImplemented()));
  39. process->setProcessChannelMode(QProcess::MergedChannels);
  40. }
  41. Airodump::~Airodump()
  42. {
  43. delete ui;
  44. if (process->state() == QProcess::Running) {
  45. utils::killProcess(process->pid());
  46. process->waitForFinished(WAIT_FOR_PROCESS);
  47. }
  48. }
  49. void Airodump::test(){
  50. }
  51. void Airodump::start(){
  52. this->startMonitor(false);
  53. }
  54. void Airodump::capture(){
  55. this->startMonitor(true);
  56. }
  57. void Airodump::setStatus(QString s){
  58. GLOBALS::STATUS = s; //ESTO NO TIENE QUE SER GLOBAL AL PUTO PROGRAMA, HAY QUE HACERLO LOCAL AL OBJETO airodump
  59. emit statusChanged(s);
  60. }
  61. void Airodump::attackBroadcast(){
  62. infoConnectionBssid infoC = this->getSelectedInfoConnectionBssid();
  63. infoESSID infoE = this->getSelectedInfoESSID();
  64. if (infoE.getBSSID().isEmpty()){
  65. utils::mostrarMensaje("Please, select a BSSID in the up table");
  66. return;
  67. }
  68. if (!utils::validMAC(infoC.getBSSID())) { //can be (not associated)
  69. if (QMessageBox::question(this, "Message", "We need any station associated to do the attack.\nWould you want to do a Fake Auth Attack?",
  70. QMessageBox::Yes, QMessageBox::No)
  71. == QMessageBox::Yes)
  72. this->doAttackAuth(infoE.getBSSID(), 30, "");
  73. return;
  74. }
  75. emit doAttackBroadcast(infoE.getBSSID(), infoC.getStation());
  76. }
  77. //depends of the STATE and the tables (if there are selected rows)
  78. void Airodump::enableCorrectOptions(QString status){
  79. if (status == "STOPPED") {
  80. utils::setBackgroundColor(this->ui->lineEditStatus, utils::RED);
  81. this->ui->groupBoxAttackOptions->setEnabled(false);
  82. this->ui->pushButtonCapture->setEnabled(false);
  83. this->ui->pushButtonCrack->setEnabled(false);
  84. }
  85. else if (status == "MONITORING") {
  86. utils::setBackgroundColor(this->ui->lineEditStatus, utils::YELLOW);
  87. this->ui->groupBoxAttackOptions->setEnabled(false);// maybe we can set to true
  88. //row selected?, then active capture and crack
  89. if (!this->ui->tableWidgetAirodumpGeneral->selectedItems().isEmpty()) {
  90. this->ui->pushButtonCapture->setEnabled(true);
  91. this->ui->pushButtonCrack->setEnabled(true);
  92. }
  93. else
  94. this->ui->pushButtonCapture->setEnabled(false);
  95. }
  96. else if (status == "CAPTURING") {
  97. utils::setBackgroundColor(this->ui->lineEditStatus, utils::GREEN);
  98. //select the unique row
  99. if (this->ui->tableWidgetAirodumpGeneral->selectedItems().isEmpty()) //to avoid infinite bucle between selectStationsAssociated and this
  100. this->ui->tableWidgetAirodumpGeneral->selectRow(0);
  101. this->ui->pushButtonCrack->setEnabled(true);
  102. this->ui->groupBoxAttackOptions->setEnabled(true);
  103. this->ui->pushButtonCapture->setEnabled(false);
  104. }
  105. }
  106. void Airodump::attackDeauth(){
  107. infoConnectionBssid infoC = this->getSelectedInfoConnectionBssid();
  108. infoESSID infoE = this->getSelectedInfoESSID();
  109. //if there are a row of below selected, we already have BSSID + MAC ASSOCIATED
  110. if (!infoC.getBSSID().isEmpty())
  111. emit doAttackDeauth(infoC.getBSSID(), 10, infoC.getStation());
  112. //if there are a row of up table selected, we have the BSSID, we can do deauth to all
  113. else if (!infoE.getBSSID().isEmpty())
  114. emit doAttackDeauth(infoE.getBSSID(), 10, "");
  115. else //nothing selected
  116. utils::mostrarMensaje("Please, select a row of tables to attack. Below table to do Deauth to One Mac Station connected (RECOMMENDED).\n" \
  117. "Up table to do a massive deauthentication to all stations connected to that BSSID.");
  118. }
  119. void Airodump::attackAuth(){
  120. infoESSID infoE = this->getSelectedInfoESSID();
  121. //if there are a row of up table selected
  122. if (!infoE.getBSSID().isEmpty())
  123. emit doAttackAuth(infoE.getBSSID(), 30, "");
  124. else //nothing selected
  125. utils::mostrarMensaje("Please, select a row of table to attack (BSSID)");
  126. }
  127. void Airodump::aircrack(){
  128. infoESSID infoE = this->getSelectedInfoESSID();
  129. //if there are a row of up table selected
  130. if (!infoE.getBSSID().isEmpty())
  131. emit doAircrack(infoE.getBSSID());
  132. else //nothing selected
  133. utils::mostrarMensaje("Please, select a row of table to attack (BSSID)");
  134. }
  135. void Airodump::selectStationsAssociated(){
  136. if (this->ui->tableWidgetAirodumpGeneral->selectedItems().isEmpty()) //FIX: to avoid crash when start with any selected row
  137. return;
  138. //since here, there are any selected row
  139. //updating enabled options
  140. this->enableCorrectOptions(GLOBALS::STATUS);
  141. //taking BSSID to see if he have any station associated
  142. const QString BSSID = this->ui->tableWidgetAirodumpGeneral->selectedItems().at(0)->data(Qt::DisplayRole).toString();
  143. //stations associated
  144. QList<QString> stations;
  145. for (int i=0; i<this->ui->tableWidgetAirodumpAux->rowCount(); ++i) {
  146. //if BSSID is in the bottom table, then he has any station associated
  147. if (this->ui->tableWidgetAirodumpAux->item(i, 0)->data(Qt::DisplayRole).toString() == BSSID) {
  148. //if the row in the bottom table is not selected
  149. if (!this->ui->tableWidgetAirodumpAux->selectedItems().contains(this->ui->tableWidgetAirodumpAux->item(i, 0))) {
  150. //select row [ONLY CAN SELECT ONE!!!!!!!!!] //log aki
  151. this->ui->tableWidgetAirodumpAux->selectRow(i);
  152. return;
  153. }
  154. //append station associated
  155. // stations.append(this->ui->tableWidgetAirodumpAux->item(i, 1)->data(Qt::DisplayRole).toString());
  156. }
  157. }
  158. //if there are any station associated, then show them
  159. /*
  160. if (stations.size() != 0)
  161. emit toLog(QString::number(stations.size()) + " station/s associated to BSSID " + BSSID +
  162. "\n" + utils::listToString(stations));
  163. */
  164. //nothing MAC associated
  165. this->ui->tableWidgetAirodumpAux->clearSelection();
  166. }
  167. void Airodump::newStationAppear(infoConnectionBssid infoC){
  168. if (GLOBALS::STATUS == "CAPTURING"){
  169. //select the latest row entered
  170. for (int i=0; i<this->ui->tableWidgetAirodumpAux->rowCount(); ++i)
  171. if (this->ui->tableWidgetAirodumpAux->item(i, 1)->data(Qt::DisplayRole).toString() == infoC.getStation()) {
  172. this->ui->tableWidgetAirodumpAux->selectRow(i);
  173. break;
  174. }
  175. }
  176. }
  177. void Airodump::startMonitor(bool capture){
  178. //init
  179. QString args;
  180. //taking arguments
  181. if (this->ui->checkBoxFilterB->isChecked()) {
  182. if (utils::validMAC(this->ui->lineEditBSSID->text()))
  183. args += (QString)" --bssid " += this->ui->lineEditBSSID->text();
  184. else
  185. utils::mostrarWarning("BSSID " + this->ui->lineEditBSSID->text() + " invalid.");
  186. }
  187. if (this->ui->checkBoxFilterC->isChecked())
  188. args += (QString)" -c " += QString::number(this->ui->spinBoxChannel->value());
  189. if (this->ui->checkBoxFilterE->isChecked())
  190. args += (QString)" --enc " += this->ui->comboBoxE->currentText();
  191. QString command;
  192. if (capture) {
  193. const infoESSID infoE = this->getSelectedInfoESSID();
  194. if (infoE.getBSSID().isEmpty()) {
  195. utils::mostrarError("You must specify a BSSID selecting a row of the up table");
  196. return;
  197. }
  198. command = (SUDO_AUX + " " + AIRODUMP_COM + " -c " + QString::number(infoE.getChannel()) + " --bssid " +
  199. infoE.getBSSID() + " -w " + CAPTURE_FOLDER + infoE.getBSSID() + " " + GLOBALS::INTERFACE);
  200. }
  201. else
  202. command = (SUDO_AUX + " " + AIRODUMP_COM + " " + args + " " + GLOBALS::INTERFACE);
  203. //stopping previus process
  204. stop();
  205. //REMOVE ANY PREVIOUS BUFFER
  206. if (QFile::exists(BUFFER_AIRODUMP_FILENAME))
  207. if (!fileM4.remove(BUFFER_AIRODUMP_FILENAME))
  208. utils::mostrarError("Error trying to remove previus .M4 file buffer");
  209. //START!
  210. process->start(command);
  211. emit toLog(command);
  212. if (!process->waitForStarted(WAIT_FOR_PROCESS))
  213. utils::mostrarError("Error al intentar ejecutar " + command);
  214. //checking errors. //Wait for reading enough information
  215. //esto hay que arreglarlo, kizas un usleep?
  216. process->waitForReadyRead(WAIT_FOR_PROCESS);
  217. process->waitForReadyRead(WAIT_FOR_PROCESS);
  218. process->waitForReadyRead(WAIT_FOR_PROCESS);
  219. process->waitForReadyRead(WAIT_FOR_PROCESS);
  220. process->waitForReadyRead(WAIT_FOR_PROCESS);
  221. process->waitForReadyRead(WAIT_FOR_PROCESS);
  222. const QString info = process->readAllStandardOutput();
  223. if (!info.contains("Elapsed")) { //maybe we can fix - se tiene que mejorar la deteccion de errores
  224. toLog(utils::htmlRojo(info));
  225. utils::mostrarError(info);
  226. utils::mostrarError("Are you sure that you have executed Airmon-ng in options\nto put interface into Monitor Mode and select correct\
  227. interface?\nSEE LOG");
  228. //stopping
  229. this->ui->pushButtonStop->click();
  230. }
  231. else if (!this->openFileM4()){
  232. utils::mostrarError("Error trying to open .M4 file");
  233. //stopping
  234. this->ui->pushButtonStop->click();
  235. }
  236. else {
  237. //starting
  238. //init vectors
  239. this->clearInfoVectors();
  240. //clear tables
  241. this->clearTables();
  242. update();
  243. //restore time elapsed
  244. this->ui->spinBoxTime->setValue(0);
  245. //init time elapsed
  246. time.start(1000);
  247. //setStatus is the latest to do (to avoid problems associated a enableCorrectOptions)
  248. if (capture)
  249. this->setStatus("CAPTURING");
  250. else
  251. this->setStatus("MONITORING");
  252. }
  253. }
  254. bool Airodump::openFileM4(){
  255. fileM4.setFileName(BUFFER_AIRODUMP_FILENAME);
  256. return fileM4.open(QIODevice::ReadOnly);
  257. }
  258. void Airodump::stop(){
  259. //terminating process
  260. if (process->state() == QProcess::Running) {
  261. utils::killProcess(process->pid());
  262. if (!process->waitForFinished(WAIT_FOR_PROCESS))
  263. utils::mostrarError("Critical. Error trying to finalize the process airodump");
  264. }
  265. //closing buffer
  266. this->fileM4.close();
  267. //de-selecting tables
  268. this->ui->tableWidgetAirodumpAux->clearSelection();
  269. this->ui->tableWidgetAirodumpGeneral->clearSelection();
  270. //status
  271. this->setStatus("STOPPED");
  272. //time elapsed
  273. time.stop();
  274. }
  275. void Airodump::update(){
  276. //fprintf(stderr, "%s\n", process->readAllStandardOutput().data());
  277. //taking BSSIDS
  278. convertInfo();
  279. //inserting values
  280. for (int i=0; !infoE[i].getBSSID().isEmpty(); ++i)
  281. insertRow(infoE[i], this->ui->tableWidgetAirodumpGeneral);
  282. for (int i=0; !infoC[i].getBSSID().isEmpty(); ++i)
  283. insertRow(infoC[i], this->ui->tableWidgetAirodumpAux);
  284. if (process->state() == QProcess::Running)
  285. QTimer::singleShot(TIME_UPDATE_AIRODUMP, this, SLOT(update()));
  286. }
  287. void Airodump::sort(){
  288. //activate sorting
  289. this->ui->tableWidgetAirodumpGeneral->setSortingEnabled(true);
  290. //0 = POWER
  291. //1 = Beacons
  292. //2 = data
  293. //3 = data/s
  294. this->ui->tableWidgetAirodumpGeneral->sortByColumn(this->ui->comboBoxSort->currentIndex() + 1, Qt::DescendingOrder);
  295. //disabling sorting
  296. this->ui->tableWidgetAirodumpGeneral->setSortingEnabled(false);
  297. }
  298. //CRITICAL FUNCTION. Convert info from buffer.
  299. int Airodump::convertInfo(){
  300. static int nInfoE, nInfoC;
  301. static QStringList fields;
  302. //close the buffer to re-read it (because it is updated all time)
  303. fileM4.close();
  304. if (!this->fileM4.open(QIODevice::ReadOnly))
  305. utils::mostrarError("Error trying to re-open .M4 to be read");
  306. //init index of vectors
  307. nInfoE = nInfoC = 0;
  308. //nothing to read?
  309. if (fileM4.readLine().isEmpty())
  310. return -1;
  311. //reading trash
  312. fileM4.readLine();
  313. //filling first table
  314. while (1) {
  315. fields = QString(fileM4.readLine()).split(',');
  316. fields.replaceInStrings(" ", "");
  317. if (fields.size() != 16)
  318. break;
  319. this->infoE[nInfoE].setAuth(fields.at(7));
  320. this->infoE[nInfoE].setBeacons(fields.at(9));
  321. this->infoE[nInfoE].setBSSID(fields.at(0));
  322. this->infoE[nInfoE].setChannel(fields.at(3));
  323. this->infoE[nInfoE].setCipher(fields.at(6));
  324. this->infoE[nInfoE].setData(fields.at(10));
  325. this->infoE[nInfoE].setDataS(fields.at(14));
  326. this->infoE[nInfoE].setEnc(fields.at(5));
  327. this->infoE[nInfoE].setMb(fields.at(4));
  328. this->infoE[nInfoE].setName(fields.at(13));
  329. this->infoE[nInfoE].setPower(fields.at(8));
  330. nInfoE++;
  331. }
  332. //reading trash
  333. fileM4.readLine();
  334. //filling second table
  335. while (1){
  336. fields = QString(fileM4.readLine()).split(',');
  337. fields.replaceInStrings(" ", "");
  338. if (fields.size() != 9)
  339. break;
  340. this->infoC[nInfoC].setBSSID(fields.at(5));
  341. this->infoC[nInfoC].setLost(fields.at(6));
  342. this->infoC[nInfoC].setPackets(fields.at(4));
  343. this->infoC[nInfoC].setPower(fields.at(3));
  344. this->infoC[nInfoC].setProbes(((QString)fields.at(8))); //aki hay caracteres erroneos
  345. this->infoC[nInfoC].setRate(fields.at(7));
  346. this->infoC[nInfoC].setStation(fields.at(0));
  347. nInfoC++;
  348. }
  349. return 1;
  350. }
  351. bool Airodump::insertRow(const infoConnectionBssid &infoC, QTableWidget *table){
  352. //infoC empty?
  353. if (infoC.getBSSID().isEmpty())
  354. return false;
  355. //init
  356. int index = 0;
  357. bool newStation = false;
  358. //is the infoC ALREADY in the table?
  359. for (index=0; index<table->rowCount(); ++index)
  360. if (table->item(index,0)->text() == infoC.getBSSID()) //yes, it is. We store the index
  361. break;
  362. //no, it is not, insert new row.
  363. if (index == table->rowCount()) {
  364. QProgressBar *p = new QProgressBar(this); //is sure that we destroy it?
  365. table->insertRow(index);
  366. table->setCellWidget(index, 2, p);
  367. p->setValue(0);
  368. newStation = true;
  369. }
  370. //insert items of row
  371. table->setItem(index, 0, utils::toItem(infoC.getBSSID()));
  372. table->setItem(index, 1, utils::toItem(infoC.getStation()));
  373. ((QProgressBar *)table->cellWidget(index,2))->setValue(infoC.getPower());
  374. table->setItem(index, 2, utils::toItem(infoC.getPower())); //we need to insert also this item to can sorting by it
  375. table->setItem(index, 3, utils::toItem(infoC.getRate()));
  376. table->setItem(index, 4, utils::toItem(infoC.getLost()));
  377. table->setItem(index, 5, utils::toItem(infoC.getPackets()));
  378. table->setItem(index, 6, utils::toItem(infoC.getProbes()));
  379. if (newStation) //new station is entered
  380. emit stationAppear(infoC);
  381. //all correct
  382. return true;
  383. }
  384. bool Airodump::insertRow(const infoESSID &info, QTableWidget *table){
  385. //info empty?
  386. if (info.getBSSID().isEmpty())
  387. return false;
  388. //init
  389. int index = 0;
  390. //is the info ALREADY in the table?
  391. for (index=0; index<table->rowCount(); ++index)
  392. if (table->item(index,0)->text() == info.getBSSID()) //yes, it is. We store the index
  393. break;
  394. //no, it is not, insert new row.
  395. if (index == table->rowCount()) {
  396. QProgressBar *p = new QProgressBar(this); //is sure that we destroy it?, SI CREO QUE SE DESTRUYE, porque el padre lo destruye cuando muere.
  397. table->insertRow(index);
  398. table->setCellWidget(index, 1, p);
  399. }
  400. //insert items of row
  401. table->setItem(index, 0, utils::toItem(info.getBSSID()));
  402. ((QProgressBar *)table->cellWidget(index,1))->setValue(info.getPowerConverted());
  403. table->setItem(index, 1, utils::toItem(info.getPowerConverted())); //we need to insert also this item to can sorting by it
  404. table->setItem(index, 2, utils::toItem(info.getBeacons()));
  405. table->setItem(index, 3, utils::toItem(info.getData()));
  406. table->setItem(index, 4, utils::toItem(info.getDataS()));
  407. table->setItem(index, 5, utils::toItem(info.getChannel()));
  408. table->setItem(index, 6, utils::toItem(info.getMb()));
  409. table->setItem(index, 7, utils::toItem(info.getEnc()));
  410. table->setItem(index, 8, utils::toItem(info.getCipher()));
  411. table->setItem(index, 9, utils::toItem(info.getAuth()));
  412. table->setItem(index, 10, utils::toItem(info.getName()));
  413. return true;
  414. }
  415. infoESSID Airodump::getSelectedInfoESSID(){
  416. infoESSID out;
  417. QList<QTableWidgetItem*> items = this->ui->tableWidgetAirodumpGeneral->selectedItems(); //one row
  418. if (items.isEmpty()) //no selection?
  419. return out; //no me mola muxo devolver una local posiblemente vacia
  420. out.setBSSID(items.at(0)->text());
  421. out.setPower(items.at(1)->text());
  422. out.setBeacons(items.at(2)->text());
  423. out.setData(items.at(3)->text());
  424. out.setDataS(items.at(4)->text());
  425. out.setChannel(items.at(5)->text());
  426. out.setMb(items.at(6)->text());
  427. out.setEnc(items.at(7)->text());
  428. out.setCipher(items.at(8)->text());
  429. out.setAuth(items.at(9)->text());
  430. out.setName(items.at(10)->text());
  431. return out;
  432. }
  433. infoConnectionBssid Airodump::getSelectedInfoConnectionBssid(){
  434. infoConnectionBssid out;
  435. QList<QTableWidgetItem*> items = this->ui->tableWidgetAirodumpAux->selectedItems(); //one row
  436. if (items.isEmpty()) //no selection?
  437. return out; //no me mola muxo devolver una local posiblemente vacia
  438. out.setBSSID(items.at(0)->text());
  439. out.setStation(items.at(1)->text());
  440. out.setPower(items.at(2)->text());
  441. out.setRate(items.at(3)->text());
  442. out.setLost(items.at(4)->text());
  443. out.setPackets(items.at(5)->text());
  444. out.setProbes(items.at(6)->text());
  445. return out;
  446. }
  447. //a implementar
  448. infoConnectionBssid Airodump::getRowInfoConnectionBssid(int row){
  449. }
  450. void Airodump::uploadTime(){
  451. this->ui->spinBoxTime->setValue(this->ui->spinBoxTime->value()+1);
  452. }
  453. void Airodump::clearInfoVectors(){
  454. infoE.clear();
  455. infoC.clear();
  456. }
  457. void Airodump::clearTables(){
  458. while (this->ui->tableWidgetAirodumpAux->rowCount() > 0)
  459. this->ui->tableWidgetAirodumpAux->removeRow(this->ui->tableWidgetAirodumpAux->rowCount()-1);
  460. while (this->ui->tableWidgetAirodumpGeneral->rowCount() > 0)
  461. this->ui->tableWidgetAirodumpGeneral->removeRow(this->ui->tableWidgetAirodumpGeneral->rowCount()-1);
  462. }