09-Jul-2019 08:24
We have a DB2 database that we need to scrub/mask SSN (Social Security) and CCN (CreditCard).
Note: This is a TCP Virtual Server as it is a database via JDBC.
iRules that work scrubbing HTTP Requests.
https://devcentral.f5.com/s/articles/irule-ccn-scrubber
https://devcentral.f5.com/s/articles/credit-card-scrubber
The challenge as I see it is either modifying one of iRules above to work with this TCP VS or seeing what other options we have to protect these VIPs. This box has ASM loaded; however I have not found anything outside of it's primary usage for protecting Web oriented traffic.
Sample text output from packet capture:
.X.Q...R
.D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!....!F..7.S...1$P....'FOR READ ONLY WITH EXTENDED INDICATORS ..*.C...$$......SELECT * FROM tblAccounts..S.A...M ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!F..[.....U ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!.......!]..n.C...h$......00000SQL11014......................... ..TESTDB ..............U................................................ACCTINT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTINT......................................ACCTCHAR..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTCHAR......................................COMMENTS..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....COMMENTS......................................DT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....DT..........C....$...2.R...,"....I....!.$...!....!P...![..........$`$B.(.S..."$..v....>..?..%.. q.T......q.....B.S...<$....q........1111111111111111...Contains an account number 1111-1111-1111-1111.2019-07-08-16.15.29.444000.....[......2111111111111111...Contains an account number 2111-1111-1111-1111.2019-07-08-16.15.53.382000...q...
....3111111111111111...Contains an account number 3111-1111-1111-1111.2019-07-08-16.18.25.071000.&.R... "....I....!.......@@@@@@@@@@@@.Y.....S$..d...02000SQLRI01F......................... ..TESTDB ............. ..........+.R...%"....I....!....!.......@@@@@@@@@@@@...S....$.......................U.X.Q...R
.D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!....!F..7.S...1$P....'FOR READ ONLY WITH EXTENDED INDICATORS ..*.C...$$......SELECT * FROM tblAccounts..S.A...M ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!F..[.....U ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!.......!]..n.C...h$......00000SQL11014......................... ..TESTDB ..............U................................................ACCTINT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTINT......................................ACCTCHAR..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTCHAR......................................COMMENTS..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....COMMENTS......................................DT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....DT..........C....$...2.R...,"....I....!.$...!....!P...![..........$`$B.(.S..."$..v....>..?..%.. q.T......q.....B.S...<$....q........1111111111111111...Contains an account number 1111-1111-1111-1111.2019-07-08-16.15.29.444000.....[......2111111111111111...Contains an account number 2111-1111-1111-1111.2019-07-08-16.15.53.382000...q...
....3111111111111111...Contains an account number 3111-1111-1111-1111.2019-07-08-16.18.25.071000.&.R... "....I....!.......@@@@@@@@@@@@.Y.....S$..d...02000SQLRI01F......................... ..TESTDB ............. ..........+.R...%"....I....!....!.......@@@@@@@@@@@@...S....$.......................p.X.Q...R
.D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!....!F..7.S...1$P....'FOR READ ONLY WITH EXTENDED INDICATORS ..*.C...$$......SELECT * FROM tblAccounts..S.A...M ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!F..[.....U ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!.......!]..n.C...h$......00000SQL11014......................... ..TESTDB ..............U................................................ACCTINT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTINT......................................ACCTCHAR..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTCHAR......................................COMMENTS..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....COMMENTS......................................DT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....DT..........C....$...2.R...,"....I....!.$...!....!P...![..........$`$B.(.S..."$..v....>..?..%.. q.T......q.....B.S...<$....q........1111111111111111...Contains an account number 1111-1111-1111-1111.2019-07-08-16.15.29.444000.....[......2111111111111111...Contains an account number 2111-1111-1111-1111.2019-07-08-16.15.53.382000...q...
....3111111111111111...Contains an account number 3111-1111-1111-1111.2019-07-08-16.18.25.071000.&.R... "....I....!.......@@@@@@@@@@@@.Y.....S$..d...02000SQLRI01F......................... ..TESTDB ............. ..........+.R...%"....I....!....!.......@@@@@@@@@@@@...S....$.......................R
/jeff
09-Jul-2019 09:03
If you already have ASM, the correct option for you is the Data Guard feature which is purpose-built for exactly your use case. See here: https://devcentral.f5.com/s/articles/the-big-ip-application-security-manager-part-8-data-guard
09-Jul-2019 09:10
Jason, Thank you for the quick response. Question, being that this is a Database i.e. a standard TCP VS would ASM be able to inspect this being that it is not HTTP?
/jeff
09-Jul-2019 09:49
Ah, hasty response on my part, didn’t fully read your question. Let me do a little digging. Not super familiar with db2...will numbers be in the clear or need binary inspection?
09-Jul-2019 12:13
Jason, No worries at all. I updated the post to make the TCP requirement more evident. The format is ASCII and EBCDIC and the numbers are in plain text.
/jeff
10-Jul-2019
09:28
- last edited on
01-Jun-2023
14:55
by
JimmyPackets
Ok, so this is tcp and cleartext data, so you have options. Looks in wireshark to be a well-understood protocol, so you can parse out by field with a TCP::collect and binary scan on the request to look for queries to any table that might have that information in it, and then activate a stream profile and use a stream match to sanitize the response data. You have to do the collection work and change the events to be TCP appropriate rather than HTTP, but this article has what you need for the CC replacement info. To add SSN for the iRule shared above, you can use this regex from this codeshare entry:
set static::ssn_regex {\d{3}-\d{2}-\d{4}}
15-Jul-2019 12:53
Jason, Thank you for the response and leads here. The article you wrote on what you did with TCP::collect/binary scan for SSL was spot on to give me a frame work to model. At this point I have more questions than answers 🙂 That said, I'm in a collect and see mode. The idea being to understand the data between Wireshark and local log. I will admit that what appears to be UTF-8 encoding when logging the TCP::payload to local log is throwing me off a bit.
Below is the current rule; however it is only firing when the database is first connected. So I'm not seeing when the actual data is queried. Feel free to let me know how far off or on track I am here.
Current iRule:
Collects Data on Server Connect, Extracts Data Length/Payload Length/Payload to local log. It does a Binary Scan using Data length, inserts into variable, and releases to the server.
when SERVER_CONNECTED {
TCP::collect
}
when SERVER_DATA {
set datalen [TCP::offset]
log local0. "Data length is : $datalen"
set payloadlen [TCP::payload length]
log local0. "Payload length is : $payloadlen"
set payload [TCP::payload]
log local0. "Collected goods : $payload"
binary scan [TCP::payload] H$datalen var1
log local0. "TCP Collect found $var1"
TCP::release
}
Output:
Jul 15 00:56:02 DEV-VE-1 tmm[64878]: Rule /DB/DB-TCP-Collect-iRule <SERVER_DATA>: Data length is : 1172
Jul 15 00:56:02 DEV-VE-1 tmm[64878]: Rule /DB/DB-TCP-Collect-iRule <SERVER_DATA>: Payload length is : 1172
Jul 15 00:56:02 DEV-VE-1 tmm[64878]: Rule /DB/DB-TCP-Collect-iRule <SERVER_DATA>: Collected goods : nÐC\xC0\x80 h$ \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x8000000SQL11014\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80 TESTDB \xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80U\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ì \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ACCTINT\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 TESTDB\xC0\x80
TBLACCOUNTS\xC0\x80\xC0\x80\xC0\x80
TBLACCOUNTS\xC0\x80\xC0\x80\xC0\x80 DB2ADMIN\xC0\x80\xC0\x80\xC0\x80ACCTINT\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80À ¸\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 ACCTCHAR\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 TESTDB\xC0\x80
TBLACCOUNTS\xC0\x80\xC0\x80\xC0\x80
TBLACCOUNTS\xC0\x80\xC0\x80\xC0\x80 DB2ADMIN\xC0\x80\xC0\x80\xC0\x80 ACCTCHAR\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80Á ¸\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 COMMENTS\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 TESTDB\xC0\x80
TBLACCOUNTS\xC0\x80\xC0\x80\xC0\x80
TBLACCOUNTS\xC0\x80\xC0\x80\xC0\x80 DB2ADMIN\xC0\x80\xC0\x80\xC0\x80 COMMENTS\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80\xC0\x80\xC0\x80\xC0\x80 \xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80‰ ¸\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 DT\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80ÿ\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80\xC0\x80 TESTDB\xC0\x80
TBLACCOUNTS\xC0\x80\xC0
Jul 15 00:56:02 DEV-VE-1 tmm[64878]: Rule /DB/DB-TCP-Collect-iRule <SERVER_DATA>: TCP Collect found 026ed0430001026824110000000000303030303053514c3131303134000000000000000000030000000700000000000000000000002020202020202020202020001254455354444220202020202020202020202000000000ff000100000000000000550001000000000000000000000000000400000000000800000000000000ec01000000000000000000000000000000000741434354494e5400000000000000000000ff000100000000000000000000000006544553544442000b54424c4143434f554e54530000000b54424c4143434f554e54530000000844423241444d494e0000000741434354494e54000000000000ff000000001400000000000000c00104b8000000000000000008000000000008414343544348415200000000000000000000ff000000000000000000000000000006544553544442000b54424c4143434f554e54530000000b54424c4143434f554e54530000000844423241444d494e000000084143435443484152000000000000ff000000000001000000000000c10104b8000000000000000008000000000008434f4d4d454e545300000000000000000000ff000000000000000000000000000006544553544442000b54424c41
/jeff
15-Jul-2019 15:04
that's because you never re-collect in the SERVER_DATA event. SERVER_CONNECTED only fires once, SERVER_DATA will fire again when data is received from the server if raised by a collect in that event. It comes after your release. For some guidance (large iRules but focus in on the release/collect mechanics), consider https://devcentral.f5.com/s/articles/starttls-server-smtp-with-cleartext-and-starttls-client-support... or https://devcentral.f5.com/s/articles/ldap-stats-measuring
16-Jul-2019 22:29
Thanks for the pointer on re invoking the TCP::collect after the release as that worked! I'm struggling with the binary scan so I'm working on a crawl, walk, run approach. For now, crawl would be what can I see and logging it, walk would be can I block user(s) starts with a particular pattern - let's call it DEVDBTEST*, allow only test CCN ranges (documented) otherwise drop and log. Run would be masking data and sending some type of alert if any of the previous were detected. The challenges I see it are, the username doesn't appear in every packet collected making it difficult to take action like drop difficult, I'm getting hits on tests in my Test CCN datagroup (key with no value i.e. a list), and I'm uncertain despite my best efforts how to log matches found in my datagroup to know I'm headed in the right direction. I really appreciate you for taking the time to provide guidance and insight!
Updated iRule:
when SERVER_CONNECTED {
TCP::collect
}
when SERVER_DATA {
set sd_datalen [TCP::offset]
log local0.info "Server Data Length is: $sd_datalen"
set sd_payload [string tolower [TCP::payload]]
#log local0.info "Server Data Payload Collected is: $sd_payload"
# Check if Card is part of authorized list
if { $sd_payload contains "DEVDBTEST" or [class match $sd_payload contains ccn_auth]} { log local0.info "Authorized Data Found" }
else { log local0.info "No Authorized Data Found :("}
TCP::release
TCP::collect
}
Datagroup
ltm data-group internal ccn_auth {
records {
1111-11 { }
111111 { }
211-11 { }
21111 { }
311-11 { }
31111 { }
}
type string
}
/jeff