Thursday, May 04, 2006

Snort - Rule Writing

I supposed to blog other stuffs but since there's someone asking me regarding snort rule, I think it would be nice to share with others. Sputera, has asked me about -

It came to my attention where any strings in "content" basically in ASCII. Now, attackers are intelligent enough. Can they translate the ASCII to HEX and detected in Snort.

WEB-IIS cmd.exe
Based on the rules, any strings with the word "cmd.exe" will trigger this alert.

Now, let say the attackers traslate it to HEX code, "63 6d 64 2e 65 78 65". Then, we write the rules content "63 6d 64 2e 65 78 65". Can or not?

But, basically HEX code are written in C/C++...

Let's correct the situation. Sputera, to clear your idea of how snort examines the packet, you should start learning looking at the packet content especially the payload itself, you should try either tcpdump or using snort in logger mode and read it with -r. Or if you find it too hard at first, try ethereal.

Snort normally will examine the payload, and the hex value normally will be converted to ascii for payload detection, so normally either the hex value "63:6d:64:2e:65:78:65" or "cmd.exe" will be detected when you using the content as payload detection method, remember content not only can be used to examine string but raw bytes. Normally attacker not translating it to hex but when the cmd.exe string sent through the wire, it will convert to binary form and translate back when it reaches the destination host and the packet is processed. That is nothing to do with bypassing the IDS, normally most of clever attackers will choose to either protocol tunneling, fragmentation or using covert channel to avoid detection of IDS instead.

And here's why it is not good to use hex value for detection but stick with the ascii strings with nocase. Before that, let's look at the default snort rule that used to detect cmd.exe through port 80 web service.

alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS \
(msg:"WEB-IIS cmd.exe access"; flow:to_server,established; \
uricontent:"cmd.exe"; nocase; classtype:web-application-attack; sid:1002; rev:7;)

Since HTTP is TCP based, flow:to_server,established is perfect for the situation where connection should be established. URIcontent is used for http normalization, you should use uricontent instead of content matching since this is about http packet inspection.

About your idea to use hex value, I write a simple rule for it.

alert tcp any any -> any 80 (msg: "HTTP cmd.exe Access"; \
flow:to_server,established; content: "|63 6d 64 2e 65 78 65|"; \
rawbytes; classtype: web-application-activity;offset:5; sid;4000005)

This rule is simple, examine packet content with
"63 6d 64 2e 65 78 65" hex value which is cmd.exe , if you are writing your own rule, put it in local.rules. I use rawbytes to avoid using http inspection.

I start running snort with

shell>snort -c /etc/snort.conf -l /nsm/snort-test/log -K ascii -i vr0

Then I tail the /nsm/snort-test/log/alert file

shell>tail -f /nsm/snort-test/log/alert

Let's see what happen when I try to test it. This part you can use netcat to connect to port 80 but I just open the url with the internet browser -

http://202.75.42.254/bigsis/cmd.exe

Both rules was hit and alert shown ....

[**] [1:1002:7] WEB-IIS cmd.exe access [**]
[Classification: Web Application Attack] [Priority: 1]
05/04-18:05:52.672196 192.168.0.50:62552 -> 202.75.42.254:80
TCP TTL:64 TOS:0x0 ID:20087 IpLen:20 DgmLen:497 DF
***AP*** Seq: 0xA818A623 Ack: 0x9637D2D2 Win: 0xFFFF TcpLen: 20

[**] [1:4000005:0] HTTP cmd.exe Access [**]
[Classification: access to a potentially vulnerable web application] [Priority:2]
05/04-18:05:52.672196 192.168.0.50:62552 -> 202.75.42.254:80
TCP TTL:64 TOS:0x0 ID:20087 IpLen:20 DgmLen:497 DF
***AP*** Seq: 0xA818A623 Ack: 0x9637D2D2 Win: 0xFFFF TcpLen: 20

When we look at the packet content, here's what I get

2006-05-04 17:02:26.970419 00:0f:3d:a0:c9:a9 (oui Unknown) > 00:0c:41:92:56:ee (
oui Unknown), IPv4, length 511: 192.168.0.50.64276 > 202.75.42.254.http: tcp 457
0x0000: 000c 4192 56ee 000f 3da0 c9a9 0800 4500 ..A.V...=.....E.
0x0010: 01f1 4764 4000 4006 3b7f c0a8 0032 ca4b ..Gd@.@.;....2.K
0x0020: 2afe fb14 0050 da63 30fb a627 b2bd 5018 *....P.c0..'..P.
0x0030: ffff f869 0000 4745 5420 2f62 6967 7369 ...i..GET./bigsi
0x0040: 732f 636d 642e 6578 6520 4854 5450 2f31 s/cmd.exe.HTTP/1
0x0050: 2e31 0d0a 486f 7374 3a20 3230 322e 3735 .1..Host:.202.75
0x0060: 2e34 322e 3235 340d 0a55 7365 722d 4167 .42.254..User-Ag
0x0070: 656e 743a 204d 6f7a 696c 6c61 2f35 2e30 ent:.Mozilla/5.0
0x0080: 2028 5831 313b 2055 3b20 4672 6565 4253 .(X11;.U;.FreeBS

I supress the output, and the packet matches the rule. However what if I'm drunk and accidentally hit the caplock :P

http://202.75.42.254/bigsis/Cmd.exe

You may notice the cmd.exe changed to Cmd.exe and this time, only the default snort rule showing

[**] [1:1002:7] WEB-IIS cmd.exe access [**]
[Classification: Web Application Attack] [Priority: 1]
05/04-18:06:10.533189 192.168.0.50:64120 -> 202.75.42.254:80
TCP TTL:64 TOS:0x0 ID:20097 IpLen:20 DgmLen:497 DF
***AP*** Seq: 0xB89146AD Ack: 0x979C40E9 Win: 0xFFFF TcpLen: 20

The rule I write is bypassed, and if we examine the packet content -

2006-05-04 18:11:50.573240 00:0f:3d:a0:c9:a9 > 00:0c:41:92:56:ee, IPv4, length 5
11: 192.168.0.50.60670 > 202.75.42.254.80: tcp 457
0x0000: 000c 4192 56ee 000f 3da0 c9a9 0800 4500 ..A.V...=.....E.
0x0010: 01f1 4e9a 4000 4006 3449 c0a8 0032 ca4b ..N.@.@.4I...2.K
0x0020: 2afe ecfe 0050 7a06 b8bb aca1 254e 5018 *....Pz.....%NP.
0x0030: ffff 8612 0000 4745 5420 2f62 6967 7369 ......GET./bigsi
0x0040: 732f 436d 642e 6578 6520 4854 5450 2f31 s/Cmd.exe.HTTP/1
0x0050: 2e31 0d0a 486f 7374 3a20 3230 322e 3735 .1..Host:.202.75
0x0060: 2e34 322e 3235 340d 0a55 7365 722d 4167 .42.254..User-Ag
0x0070: 656e 743a 204d 6f7a 696c 6c61 2f35 2e30 ent:.Mozilla/5.0
0x0080: 2028 5831 313b 2055 3b20 4672 6565 4253 .(X11;.U;.FreeBS

The Cmd.exe turns out to be "43 6d 64 2e 65 78 65". The default rule which matching with case insensitive seems to be better choice in this situation, the hex value is good when we want to detect those non-printable data such as : which is 3a in hex value. This has been mentionned in this tutorial by Vorant.

Your idea of using hex value in this situation is bad since it is easily bypassed and you may need to write multiple rules if you want to detect cmd.exe, CMD.EXE, cMD.exe and etc. That's not a right way. I suggest for anyone who want to learn to write snort rule, for me the best reference is still Snort Manual where you can download from www.snort.org.

By the way, the hex value here has nothing to do with C/C++, you remind me of one CEH Conductor who tells me that the hex value has something to do with assembly language and you have to learn assembly language to understand it.

Sputera, I hope that helps.

Cheers (:])

6 comments:

Joel Esler said...

Besides the fact that it makes it easier to read. ;)

Small correction Geek...

You use "rawbytes" in the rule. If you use rawbytes it gets this data from the global DecodeBuffer. The only thing that writes to to the global DecodeBuffer is the telnet preprocessor. Therefore, you don't need it at all (unless you are analyzing telnet traffic, which, you aren't)

On a second note, anytime you are going to do a content match for a metacharacter that you would have to escape inside of a content buffer, it's good to specify the hex equiv. (Those characters are : ; \ and ". However, since cmd.exe is being looked for in the uri, the http_inspect preproc will decode that for ya. So uricontent:"cmd.exe"; nocase; would be appropriate. It prevents obfuscation and it keeps your sanity.

geek00L said...

joel,

Thanks for the comment :). It is always nice to hear from you.

sPutera said...

geek00l,

thanks for your reply. i understand that especially the payload but... let say that the attacker really using HEX code to attack (e.g in URL). Lets assume this.

I have one vulnerable machine. And the attacker try to get the passwd info. Rather than he/she use this code:

http://vulnerable/index.php?file=etc/passwd

The attacker use this code with hex:-

http://vulnerable/%69%6e%64%65%78%2e%70%68%70%3f%66%69%6c%65%3d%65%74%63%2f%70%61%73%73%77%64

How snort detect it? Is there any preprocessor inside snort to translate it?

sPutera said...

thanks for your explaination.

geek00L said...

sputera,

You don't have to worry of that part, if you are talking about unicode stuffs, the http normalization will do it all for you.

t3chamngoan said...

So, in my assignment I have to detect a request of webpage containing "Exam" in the title tag. I found out that the html code is encoded with gzip, and then being sent. I used rawbytes but it didn't work. Can you please help me in this case?