#include "airodump.h" #include "ui_airodump.h" Airodump::Airodump(QWidget *parent) : QWidget(parent), ui(new Ui::Airodump) { ui->setupUi(this); process = new QProcess(this); //initializing //this->ui->pushButtonStop->hide(); //connecting buttons connect(this->ui->pushButtonStart, SIGNAL(clicked()), this, SLOT(start())); connect(this->ui->pushButtonStop, SIGNAL(clicked()), this, SLOT(stop())); //connect button to sort connect(this->ui->pushButtonSort, SIGNAL(clicked()), this, SLOT(sort())); //connect things to trigger associated stations connect(this->ui->tableWidgetAirodumpGeneral, SIGNAL(itemSelectionChanged()), this, SLOT(selectStationsAssociated())); //below table, signal when new station appear connect(this, SIGNAL(stationAppear(infoConnectionBssid)), this, SLOT(newStationAppear(infoConnectionBssid))); //attack deauth connect(this->ui->pushButtonDeauth, SIGNAL(clicked()), this, SLOT(attackDeauth())); //attack auth connect(this->ui->pushButtonAuth, SIGNAL(clicked()), this, SLOT(attackAuth())); //attack broadcast connect(this->ui->pushButtonBroadcast, SIGNAL(clicked()), this, SLOT(attackBroadcast())); //aircrack connect(this->ui->pushButtonCrack, SIGNAL(clicked()), this, SLOT(aircrack())); //capture connect(this->ui->pushButtonCapture, SIGNAL(clicked()), this, SLOT(capture())); //status connect(this, SIGNAL(statusChanged(QString)), this->ui->lineEditStatus, SLOT(setText(QString))); connect(this, SIGNAL(statusChanged(QString)), this, SLOT(enableCorrectOptions(QString))); //time elapsed connect(&this->time, SIGNAL(timeout()), this, SLOT(uploadTime())); //not implemented connect(this->ui->pushButtonARP, SIGNAL(clicked()), this, SLOT(notImplemented())); connect(this->ui->pushButtonChop, SIGNAL(clicked()), this, SLOT(notImplemented())); connect(this->ui->pushButtonChop, SIGNAL(clicked()), this, SLOT(notImplemented())); process->setProcessChannelMode(QProcess::MergedChannels); } Airodump::~Airodump() { delete ui; if (process->state() == QProcess::Running) { utils::killProcess(process->pid()); process->waitForFinished(WAIT_FOR_PROCESS); } } void Airodump::test(){ } void Airodump::start(){ this->startMonitor(false); } void Airodump::capture(){ this->startMonitor(true); } void Airodump::setStatus(QString s){ GLOBALS::STATUS = s; //ESTO NO TIENE QUE SER GLOBAL AL PUTO PROGRAMA, HAY QUE HACERLO LOCAL AL OBJETO airodump emit statusChanged(s); } void Airodump::attackBroadcast(){ infoConnectionBssid infoC = this->getSelectedInfoConnectionBssid(); infoESSID infoE = this->getSelectedInfoESSID(); if (infoE.getBSSID().isEmpty()){ utils::mostrarMensaje("Please, select a BSSID in the up table"); return; } if (!utils::validMAC(infoC.getBSSID())) { //can be (not associated) if (QMessageBox::question(this, "Message", "We need any station associated to do the attack.\nWould you want to do a Fake Auth Attack?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) this->doAttackAuth(infoE.getBSSID(), 30, ""); return; } emit doAttackBroadcast(infoE.getBSSID(), infoC.getStation()); } //depends of the STATE and the tables (if there are selected rows) void Airodump::enableCorrectOptions(QString status){ if (status == "STOPPED") { utils::setBackgroundColor(this->ui->lineEditStatus, utils::RED); this->ui->groupBoxAttackOptions->setEnabled(false); this->ui->pushButtonCapture->setEnabled(false); this->ui->pushButtonCrack->setEnabled(false); } else if (status == "MONITORING") { utils::setBackgroundColor(this->ui->lineEditStatus, utils::YELLOW); this->ui->groupBoxAttackOptions->setEnabled(false);// maybe we can set to true //row selected?, then active capture and crack if (!this->ui->tableWidgetAirodumpGeneral->selectedItems().isEmpty()) { this->ui->pushButtonCapture->setEnabled(true); this->ui->pushButtonCrack->setEnabled(true); } else this->ui->pushButtonCapture->setEnabled(false); } else if (status == "CAPTURING") { utils::setBackgroundColor(this->ui->lineEditStatus, utils::GREEN); //select the unique row if (this->ui->tableWidgetAirodumpGeneral->selectedItems().isEmpty()) //to avoid infinite bucle between selectStationsAssociated and this this->ui->tableWidgetAirodumpGeneral->selectRow(0); this->ui->pushButtonCrack->setEnabled(true); this->ui->groupBoxAttackOptions->setEnabled(true); this->ui->pushButtonCapture->setEnabled(false); } } void Airodump::attackDeauth(){ infoConnectionBssid infoC = this->getSelectedInfoConnectionBssid(); infoESSID infoE = this->getSelectedInfoESSID(); //if there are a row of below selected, we already have BSSID + MAC ASSOCIATED if (!infoC.getBSSID().isEmpty()) emit doAttackDeauth(infoC.getBSSID(), 10, infoC.getStation()); //if there are a row of up table selected, we have the BSSID, we can do deauth to all else if (!infoE.getBSSID().isEmpty()) emit doAttackDeauth(infoE.getBSSID(), 10, ""); else //nothing selected utils::mostrarMensaje("Please, select a row of tables to attack. Below table to do Deauth to One Mac Station connected (RECOMMENDED).\n" \ "Up table to do a massive deauthentication to all stations connected to that BSSID."); } void Airodump::attackAuth(){ infoESSID infoE = this->getSelectedInfoESSID(); //if there are a row of up table selected if (!infoE.getBSSID().isEmpty()) emit doAttackAuth(infoE.getBSSID(), 30, ""); else //nothing selected utils::mostrarMensaje("Please, select a row of table to attack (BSSID)"); } void Airodump::aircrack(){ infoESSID infoE = this->getSelectedInfoESSID(); //if there are a row of up table selected if (!infoE.getBSSID().isEmpty()) emit doAircrack(infoE.getBSSID()); else //nothing selected utils::mostrarMensaje("Please, select a row of table to attack (BSSID)"); } void Airodump::selectStationsAssociated(){ if (this->ui->tableWidgetAirodumpGeneral->selectedItems().isEmpty()) //FIX: to avoid crash when start with any selected row return; //since here, there are any selected row //updating enabled options this->enableCorrectOptions(GLOBALS::STATUS); //taking BSSID to see if he have any station associated const QString BSSID = this->ui->tableWidgetAirodumpGeneral->selectedItems().at(0)->data(Qt::DisplayRole).toString(); //stations associated QList<QString> stations; for (int i=0; i<this->ui->tableWidgetAirodumpAux->rowCount(); ++i) { //if BSSID is in the bottom table, then he has any station associated if (this->ui->tableWidgetAirodumpAux->item(i, 0)->data(Qt::DisplayRole).toString() == BSSID) { //if the row in the bottom table is not selected if (!this->ui->tableWidgetAirodumpAux->selectedItems().contains(this->ui->tableWidgetAirodumpAux->item(i, 0))) { //select row [ONLY CAN SELECT ONE!!!!!!!!!] //log aki this->ui->tableWidgetAirodumpAux->selectRow(i); return; } //append station associated // stations.append(this->ui->tableWidgetAirodumpAux->item(i, 1)->data(Qt::DisplayRole).toString()); } } //if there are any station associated, then show them /* if (stations.size() != 0) emit toLog(QString::number(stations.size()) + " station/s associated to BSSID " + BSSID + "\n" + utils::listToString(stations)); */ //nothing MAC associated this->ui->tableWidgetAirodumpAux->clearSelection(); } void Airodump::newStationAppear(infoConnectionBssid infoC){ if (GLOBALS::STATUS == "CAPTURING"){ //select the latest row entered for (int i=0; i<this->ui->tableWidgetAirodumpAux->rowCount(); ++i) if (this->ui->tableWidgetAirodumpAux->item(i, 1)->data(Qt::DisplayRole).toString() == infoC.getStation()) { this->ui->tableWidgetAirodumpAux->selectRow(i); break; } } } void Airodump::startMonitor(bool capture){ //init QString args; //taking arguments if (this->ui->checkBoxFilterB->isChecked()) { if (utils::validMAC(this->ui->lineEditBSSID->text())) args += (QString)" --bssid " += this->ui->lineEditBSSID->text(); else utils::mostrarWarning("BSSID " + this->ui->lineEditBSSID->text() + " invalid."); } if (this->ui->checkBoxFilterC->isChecked()) args += (QString)" -c " += QString::number(this->ui->spinBoxChannel->value()); if (this->ui->checkBoxFilterE->isChecked()) args += (QString)" --enc " += this->ui->comboBoxE->currentText(); QString command; if (capture) { const infoESSID infoE = this->getSelectedInfoESSID(); if (infoE.getBSSID().isEmpty()) { utils::mostrarError("You must specify a BSSID selecting a row of the up table"); return; } command = (SUDO_AUX + " " + AIRODUMP_COM + " -c " + QString::number(infoE.getChannel()) + " --bssid " + infoE.getBSSID() + " -w " + CAPTURE_FOLDER + infoE.getBSSID() + " " + GLOBALS::INTERFACE); } else command = (SUDO_AUX + " " + AIRODUMP_COM + " " + args + " " + GLOBALS::INTERFACE); //stopping previus process stop(); //REMOVE ANY PREVIOUS BUFFER if (QFile::exists(BUFFER_AIRODUMP_FILENAME)) if (!fileM4.remove(BUFFER_AIRODUMP_FILENAME)) utils::mostrarError("Error trying to remove previus .M4 file buffer"); //START! process->start(command); emit toLog(command); if (!process->waitForStarted(WAIT_FOR_PROCESS)) utils::mostrarError("Error al intentar ejecutar " + command); //checking errors. //Wait for reading enough information //esto hay que arreglarlo, kizas un usleep? process->waitForReadyRead(WAIT_FOR_PROCESS); process->waitForReadyRead(WAIT_FOR_PROCESS); process->waitForReadyRead(WAIT_FOR_PROCESS); process->waitForReadyRead(WAIT_FOR_PROCESS); process->waitForReadyRead(WAIT_FOR_PROCESS); process->waitForReadyRead(WAIT_FOR_PROCESS); const QString info = process->readAllStandardOutput(); if (!info.contains("Elapsed")) { //maybe we can fix - se tiene que mejorar la deteccion de errores toLog(utils::htmlRojo(info)); utils::mostrarError(info); utils::mostrarError("Are you sure that you have executed Airmon-ng in options\nto put interface into Monitor Mode and select correct\ interface?\nSEE LOG"); //stopping this->ui->pushButtonStop->click(); } else if (!this->openFileM4()){ utils::mostrarError("Error trying to open .M4 file"); //stopping this->ui->pushButtonStop->click(); } else { //starting //init vectors this->clearInfoVectors(); //clear tables this->clearTables(); update(); //restore time elapsed this->ui->spinBoxTime->setValue(0); //init time elapsed time.start(1000); //setStatus is the latest to do (to avoid problems associated a enableCorrectOptions) if (capture) this->setStatus("CAPTURING"); else this->setStatus("MONITORING"); } } bool Airodump::openFileM4(){ fileM4.setFileName(BUFFER_AIRODUMP_FILENAME); return fileM4.open(QIODevice::ReadOnly); } void Airodump::stop(){ //terminating process if (process->state() == QProcess::Running) { utils::killProcess(process->pid()); if (!process->waitForFinished(WAIT_FOR_PROCESS)) utils::mostrarError("Critical. Error trying to finalize the process airodump"); } //closing buffer this->fileM4.close(); //de-selecting tables this->ui->tableWidgetAirodumpAux->clearSelection(); this->ui->tableWidgetAirodumpGeneral->clearSelection(); //status this->setStatus("STOPPED"); //time elapsed time.stop(); } void Airodump::update(){ //fprintf(stderr, "%s\n", process->readAllStandardOutput().data()); //taking BSSIDS convertInfo(); //inserting values for (int i=0; !infoE[i].getBSSID().isEmpty(); ++i) insertRow(infoE[i], this->ui->tableWidgetAirodumpGeneral); for (int i=0; !infoC[i].getBSSID().isEmpty(); ++i) insertRow(infoC[i], this->ui->tableWidgetAirodumpAux); if (process->state() == QProcess::Running) QTimer::singleShot(TIME_UPDATE_AIRODUMP, this, SLOT(update())); } void Airodump::sort(){ //activate sorting this->ui->tableWidgetAirodumpGeneral->setSortingEnabled(true); //0 = POWER //1 = Beacons //2 = data //3 = data/s this->ui->tableWidgetAirodumpGeneral->sortByColumn(this->ui->comboBoxSort->currentIndex() + 1, Qt::DescendingOrder); //disabling sorting this->ui->tableWidgetAirodumpGeneral->setSortingEnabled(false); } //CRITICAL FUNCTION. Convert info from buffer. int Airodump::convertInfo(){ static int nInfoE, nInfoC; static QStringList fields; //close the buffer to re-read it (because it is updated all time) fileM4.close(); if (!this->fileM4.open(QIODevice::ReadOnly)) utils::mostrarError("Error trying to re-open .M4 to be read"); //init index of vectors nInfoE = nInfoC = 0; //nothing to read? if (fileM4.readLine().isEmpty()) return -1; //reading trash fileM4.readLine(); //filling first table while (1) { fields = QString(fileM4.readLine()).split(','); fields.replaceInStrings(" ", ""); if (fields.size() != 16) break; this->infoE[nInfoE].setAuth(fields.at(7)); this->infoE[nInfoE].setBeacons(fields.at(9)); this->infoE[nInfoE].setBSSID(fields.at(0)); this->infoE[nInfoE].setChannel(fields.at(3)); this->infoE[nInfoE].setCipher(fields.at(6)); this->infoE[nInfoE].setData(fields.at(10)); this->infoE[nInfoE].setDataS(fields.at(14)); this->infoE[nInfoE].setEnc(fields.at(5)); this->infoE[nInfoE].setMb(fields.at(4)); this->infoE[nInfoE].setName(fields.at(13)); this->infoE[nInfoE].setPower(fields.at(8)); nInfoE++; } //reading trash fileM4.readLine(); //filling second table while (1){ fields = QString(fileM4.readLine()).split(','); fields.replaceInStrings(" ", ""); if (fields.size() != 9) break; this->infoC[nInfoC].setBSSID(fields.at(5)); this->infoC[nInfoC].setLost(fields.at(6)); this->infoC[nInfoC].setPackets(fields.at(4)); this->infoC[nInfoC].setPower(fields.at(3)); this->infoC[nInfoC].setProbes(((QString)fields.at(8))); //aki hay caracteres erroneos this->infoC[nInfoC].setRate(fields.at(7)); this->infoC[nInfoC].setStation(fields.at(0)); nInfoC++; } return 1; } bool Airodump::insertRow(const infoConnectionBssid &infoC, QTableWidget *table){ //infoC empty? if (infoC.getBSSID().isEmpty()) return false; //init int index = 0; bool newStation = false; //is the infoC ALREADY in the table? for (index=0; index<table->rowCount(); ++index) if (table->item(index,0)->text() == infoC.getBSSID()) //yes, it is. We store the index break; //no, it is not, insert new row. if (index == table->rowCount()) { QProgressBar *p = new QProgressBar(this); //is sure that we destroy it? table->insertRow(index); table->setCellWidget(index, 2, p); p->setValue(0); newStation = true; } //insert items of row table->setItem(index, 0, utils::toItem(infoC.getBSSID())); table->setItem(index, 1, utils::toItem(infoC.getStation())); ((QProgressBar *)table->cellWidget(index,2))->setValue(infoC.getPower()); table->setItem(index, 2, utils::toItem(infoC.getPower())); //we need to insert also this item to can sorting by it table->setItem(index, 3, utils::toItem(infoC.getRate())); table->setItem(index, 4, utils::toItem(infoC.getLost())); table->setItem(index, 5, utils::toItem(infoC.getPackets())); table->setItem(index, 6, utils::toItem(infoC.getProbes())); if (newStation) //new station is entered emit stationAppear(infoC); //all correct return true; } bool Airodump::insertRow(const infoESSID &info, QTableWidget *table){ //info empty? if (info.getBSSID().isEmpty()) return false; //init int index = 0; //is the info ALREADY in the table? for (index=0; index<table->rowCount(); ++index) if (table->item(index,0)->text() == info.getBSSID()) //yes, it is. We store the index break; //no, it is not, insert new row. if (index == table->rowCount()) { QProgressBar *p = new QProgressBar(this); //is sure that we destroy it?, SI CREO QUE SE DESTRUYE, porque el padre lo destruye cuando muere. table->insertRow(index); table->setCellWidget(index, 1, p); } //insert items of row table->setItem(index, 0, utils::toItem(info.getBSSID())); ((QProgressBar *)table->cellWidget(index,1))->setValue(info.getPowerConverted()); table->setItem(index, 1, utils::toItem(info.getPowerConverted())); //we need to insert also this item to can sorting by it table->setItem(index, 2, utils::toItem(info.getBeacons())); table->setItem(index, 3, utils::toItem(info.getData())); table->setItem(index, 4, utils::toItem(info.getDataS())); table->setItem(index, 5, utils::toItem(info.getChannel())); table->setItem(index, 6, utils::toItem(info.getMb())); table->setItem(index, 7, utils::toItem(info.getEnc())); table->setItem(index, 8, utils::toItem(info.getCipher())); table->setItem(index, 9, utils::toItem(info.getAuth())); table->setItem(index, 10, utils::toItem(info.getName())); return true; } infoESSID Airodump::getSelectedInfoESSID(){ infoESSID out; QList<QTableWidgetItem*> items = this->ui->tableWidgetAirodumpGeneral->selectedItems(); //one row if (items.isEmpty()) //no selection? return out; //no me mola muxo devolver una local posiblemente vacia out.setBSSID(items.at(0)->text()); out.setPower(items.at(1)->text()); out.setBeacons(items.at(2)->text()); out.setData(items.at(3)->text()); out.setDataS(items.at(4)->text()); out.setChannel(items.at(5)->text()); out.setMb(items.at(6)->text()); out.setEnc(items.at(7)->text()); out.setCipher(items.at(8)->text()); out.setAuth(items.at(9)->text()); out.setName(items.at(10)->text()); return out; } infoConnectionBssid Airodump::getSelectedInfoConnectionBssid(){ infoConnectionBssid out; QList<QTableWidgetItem*> items = this->ui->tableWidgetAirodumpAux->selectedItems(); //one row if (items.isEmpty()) //no selection? return out; //no me mola muxo devolver una local posiblemente vacia out.setBSSID(items.at(0)->text()); out.setStation(items.at(1)->text()); out.setPower(items.at(2)->text()); out.setRate(items.at(3)->text()); out.setLost(items.at(4)->text()); out.setPackets(items.at(5)->text()); out.setProbes(items.at(6)->text()); return out; } //a implementar infoConnectionBssid Airodump::getRowInfoConnectionBssid(int row){ } void Airodump::uploadTime(){ this->ui->spinBoxTime->setValue(this->ui->spinBoxTime->value()+1); } void Airodump::clearInfoVectors(){ infoE.clear(); infoC.clear(); } void Airodump::clearTables(){ while (this->ui->tableWidgetAirodumpAux->rowCount() > 0) this->ui->tableWidgetAirodumpAux->removeRow(this->ui->tableWidgetAirodumpAux->rowCount()-1); while (this->ui->tableWidgetAirodumpGeneral->rowCount() > 0) this->ui->tableWidgetAirodumpGeneral->removeRow(this->ui->tableWidgetAirodumpGeneral->rowCount()-1); }