Snort mailing list archives
Re: MSSQL False Neg
From: Matt Olney <molney () sourcefire com>
Date: Tue, 1 Dec 2009 19:14:57 -0500
So, I thought it might be interesting for folks to see how I approached the false neg report, I have my full notes below for those who want to see how we work, but here is the meat of my findings (also forgive any formatting issues, I C&P alot of this from VI, and there is a ton of data in here): OK, so after our jump, we land at offset 98 from the begining of the payload. This puts us 8 bytes behind the begining of the username field (this is because of our TDS packet header, which is 8 bytes). We then do the content check 8 bytes in distance from the doe pointer. The DOE pointer is set by the byte_jump, so is at 0x62 (98). 8 bytes from there is 0x6a (106). The payload begins at packet location 0x36, if we add 0x36 to 0x6a, we get A0. At A0 we have: 00a0 73 00 61 00 b3 a5 xx 00 xx 00 xx 00 xx 00 xx 00 s.a...x.x.x.x.x. A perfect match for "s|00|a|00" aka "|73 00 61 00|". The rule seems to be correct, I'm thinking there is a thresholding issue somewhere. Looking at it, it looks like it should alert if you see 5 packets in a 2 second period that match this rule. If you want to check the non-thresholding portion of the rule, try the following local rule: alert tcp $EXTERNAL_NET any -> $SQL_SERVERS 1433 (msg:"SQL SA brute force login attempt TDS v7/8"; flow:to_server,established; content:"|10|"; depth:1; content:"|00 00|"; depth:2; offset:34; content:"|00 00 00 00|"; depth:4; offset:64; pcre:"/^.{12}(\x00|\x01)\x00\x00(\x70|\x71)/smi"; byte_jump:2,48,little,from_beginning; content:"s|00|a|00|"; within:4; distance:8; nocase; reference:bugtraq,4797; reference:cve,2000-1209; reference:nessus,10673; classtype:suspicious-login; sid:111113543;) OK, stop reading if you're not interested in gory details, including an oversight on my part: First, I had to break the packet just into the payload section. Then I ran through the packet and established what it was the rule was looking for. You'll note that I failed to grab the within/distance modifier to the final content match, so I decided to hand decode the packet. Bill's reference he was using was perfect for protocol decoding. At first I didn't know what the first 8 bytes were, but I found the header details further up in Bill's reference. Once I decoded the patcket, I understood better what we were looking for. Then I was able to see that we ended up 8 bytes short of the actual location of the username. It was immediately obvious that this was because of the 8 byte header. When I rechecked the rule, I saw that the correct modifiers were already in place: distance 8: within: 4 (order not important for these modifiers). The distance/within pair indicates that the move is relative to the pointer, and the distance value is what moves the pointer prior to the content check. The check must then pass within the number of bytes in the within field. In this case s|00|a|00| fits exactly in the 4 byte parameter, so you are essentially saying these 4 bytes MUST occur 8 bytes away. I even wondered if the port was wrong, so I decoded the eth/ip/tcp headers (By the way, Bill, very clever obfuscating the checksum so that your IP obfuscation was more effective...NICE) But everything checked out there as well. So, I was pretty confident we were good. I also pulled our old notes on this bug and grabbed the test pcap we had (generated by Alex, actually using a sql brute force tool). Since this is rev: 4, I was hoping to see some evolution of the rule, but the rule in its current state is actually how it originally written. All of the updates have been to add to the documentation. I reran the pcap with our rules and got a positive result. I then wanted to check the thresholding, so I pulled the thresholding out of the rule, and placed them both in a local rules file. Here was the output (sid 1 was the unthresholded rule: Snort Test Suite v.0.3.0 Alerts: 1:1:0 SQL SA brute force login attempt TDS v7/8 Alerts: 470 1:3543:4 SQL SA brute force login attempt TDS v7/8 Alerts: 94 So right now, I >>THINK<< we're good, both on detection and on the thresholding....so now we have to figure out why you aren't working. Let me know how your tests go. ====BEGIN NOTES==== [Layer 2/3 HEADERS] Eth 00 14 bf 52 fe 40 dst 00 d0 2b 77 75 01 src 08 00 type IP 45 Ver 4, Header size 20 TOS 00 bc Total length 1e 56 ID 40 00 Flags and frag info 6c TTL 06 Protocol (TCP) xx xx Checksum 79 0b 50 ce 121.11.80.206 (Chinanet, full /24 block...I'm guessing this was live attack traffic) xx xx xx 7a xx.xx.xx.122 TCP 08 2b src 2091 05 99 dst 1433 (Correct port for rule) a4 51 cc 4d checksum b1 be 2b 43 ack number 50 18 hdr len/reservered/flags (ack/psh set flags consistent with stream state) ff ff window size 3d 81 tcp checksum 00 00 urgent pointer [Detection Breakdown] content:"|10|"; depth: 1; 10 content:"|00 00|"; depth: 2; offset: 34; 00 00 content:"|00 00|"; depth: 4; offset: 64; 00 00 00 00 pcre:"/^.{12}(\x00|\x01)\x00\x00(\x70|\x71)/smi"; 10 01 00 94 00 00 01 00 8c 00 00 00 01 00 00 71 byte_jump:2,48,little,from_beginning; 62 00 [Read little endian, decimal: 98] content:"s|00|a|00|"; 44 00 57 00 "D" 00 "W" 00 Original packet data, serilalized: 10 01 00 94 00 00 01 00 8c 00 00 00 01 00 00 71 00 00 00 00 00 00 00 07 d0 19 00 00 00 00 00 00 e0 03 00 00 20 fe ff ff 04 08 00 00 56 00 06 00 62 00 02 00 66 00 01 00 68 00 00 00 68 00 0e 00 00 00 00 00 84 00 04 00 8c 00 00 00 8c 00 00 00 00 1c 25 5b 6f ff 00 00 00 00 8c 00 00 00 44 00 57 00 44 00 57 00 34 00 44 00 73 00 61 00 b3 a5 xx 00 xx 00 2e 00 xx 00 xx 00 xx 00 2e 00 xx 00 xx 00 xx 00 2e 00 31 00 32 00 32 00 4f 00 44 00 42 Original packet data, protocol decoded: [TDS Packet Header] Packet type: 10 (TDS 7.0 login packet) Last Packet indicator: 01 Packet Size: 00 94 Unknown: 00 00 01 00 [Login Packet Decode] Total Packet Size [4]: 8c 00 00 00 4 TDS Version [4]: 01 00 00 71 8 Packet Size [4]: 00 00 00 00 12 Client Version Program [4]: 00 00 00 07 16 PID of Client [4]: d0 19 00 00 20 Connection ID [4]: 00 00 00 00 24 Option Flags 1 [1]: e0 25 Option Flags 2 [1]: 03 26 Sql Type Flags [1]: 00 27 reserved flags [1, mbz]: 00 28 time zone [4]: 20 fe ff ff 32 Collation Info [4]: 04 08 00 00 36 Position of client hostname [2] 56 00 [86 decimal] 38 Hostname length [2] 06 00 40 Position of username [2]: 62 00 [98 decimal] 42 Username length [2]: 02 00 44 Position of password [2]: 66 00 [102 decimal] 46 Password length [2]: 01 00 48 Position of app name [2]: 68 00 [104 decimal] 50 Length of app name [2]: 00 00 52 Position of server name [2]: 68 00 [104 decimal] 54 Length of server name [2]: 0e 00 56 Int16 [2, mbz] [2]: 00 00 58 Int16 [2, mbz] [2]: 00 00 60 Position of library name [2]: 84 00 [132 decimal] 62 Length of library name [2]: 04 00 64 Position of language [2]: 8c 00 [132 decimal] 66 Length of language [2]: 00 00 68 Position of database name [2]: 8c 00 [132 decimal] 70 Length of database name [2]: 00 00 72 Mac address of the client [6]: 00 1c 25 5b 6f ff 78 Position of auth portion [2]: 00 00 80 NT Auth Length [2]: 00 00 82 Next position [2]: 8c 00 [132 decimal] 84 Int16 [2, mbz]: 00 00 86 Hostname [n(6)]: 44 00 57 00 44 00 57 00 34 00 44 00 98 (DWDW4D) Username [n(2)]: 73 00 61 00 102 (sa) Password [n(1)]: b3 a5 104 (encrypted) Server Name [n(14)]: xx 00 xx 00 2e 00 xx 00 xx 00 xx 00 2e 00 xx 00 xx 00 xx 00 2e 00 31 00 32 00 32 00 132 (xx.xxx.xxx.122) Library Name [n(4)]: 4f 00 44 00 42 00 43 00 140 (ODBC) OK...so we check: content:"|10|"; depth: 1; [Not immediately apparent what this is, as it is part of the undescribed header] content:"|00 00|"; depth: 2; offset: 34; [Checking the Sql Flags and the Reserved flags are 00 00] content:"|00 00 00 00|"; depth:4; offset:64; [Checking the 4 must-be-zero bytes at offset 58 and 60] pcre:"/^.{12}(\x00|\x01)\x00\x00(\x70|\x71)/smi"; [Verifying that we have an appropriate version field at offset 8] byte_jump:2,48,little,from_beginning; [Grab the offset of Username, jump the offset from begining of packet value here is 62 hex, 98 decimal] content:"s|00|a|00|"; within 4; distance: 8; [Check for username "sa"] OK, so after our jump, we land at offset 98 from the begining of the payload. This puts us 8 bytes behind the begining of the username field (this is because of our TDS packet header, which is 8 bytes). We then do the content check 8 bytes in distance from the doe pointer. The DOE pointer is set by the byte_jump, so is at 0x62 (98). 8 bytes from there is 0x6a (106). The payload begins at packet location 0x36, if we add 0x36 to 0x6a, we get A0. At A0 we have: 00a0: 73 00 61 00 b3 a5 xx 00 xx 00 xx 00 xx 00 xx 00 s.a...x.x.x.x.x. A perfect match for "s|00|a|00" aka "|73 00 61 00|". The rule seems to be correct, I'm thinking there is a thresholding issue somewhere. alert tcp $EXTERNAL_NET any -> $SQL_SERVERS 1433 (msg:"SQL SA brute force login attempt TDS v7/8"; flow:to_server,established; content:"|10|"; depth:1; content:"|00 00|"; depth:2; offset:34; content:"|00 00 00 00|"; depth:4; offset:64; pcre:"/^.{12}(\x00|\x01)\x00\x00(\x70|\x71)/smi"; byte_jump:2,48,little,from_beginning; content:"s|00|a|00|"; within:4; distance:8; nocase; threshold:type threshold, track by_src, count 5, seconds 2; reference:bugtraq,4797; reference:cve,2000-1209; reference:nessus,10673; classtype:suspicious-login; sid:3543; rev:4;) ------------------------------------------------------------------------------ Join us December 9, 2009 for the Red Hat Virtual Experience, a free event focused on virtualization and cloud computing. Attend in-depth sessions from your desk. Your couch. Anywhere. http://p.sf.net/sfu/redhat-sfdev2dev _______________________________________________ Snort-sigs mailing list Snort-sigs () lists sourceforge net https://lists.sourceforge.net/lists/listinfo/snort-sigs
Current thread:
- MSSQL False Neg Bill Scherr IV (Dec 01)
- Re: MSSQL False Neg Alex Kirk (Dec 01)
- Re: MSSQL False Neg Bill Scherr IV (Dec 01)
- Re: MSSQL False Neg Nigel Houghton (Dec 01)
- Re: MSSQL False Neg Matt Olney (Dec 01)
- Re: MSSQL False Neg Matt Olney (Dec 01)
- Re: MSSQL False Neg Bill Scherr IV (Dec 01)
- Re: MSSQL False Neg Bill Scherr IV (Dec 01)
- Re: MSSQL False Neg Alex Kirk (Dec 01)
- Re: MSSQL False Neg Bill Scherr IV (Dec 01)