Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for boolean datatypes on mssql #18872

Merged
merged 1 commit into from
Feb 26, 2024

Conversation

zgoldman-r7
Copy link
Contributor

@zgoldman-r7 zgoldman-r7 commented Feb 21, 2024

In newer TDS Protocol versions, two different bit datatypes were added, one that allows null and one that doesn't, to allow for boolean support. To this point, our MSSQL code does not support these values, and causes "unknown column type" errors.

Verification

List the steps needed to make sure this thing works

  • change mssql_query to query in lib/rex/post/mssql/ui/console.rb (PR incoming)
  • Start msfconsole
  • spin up an mssql instance in your vm
  • create a table with two different columns of type bit, one with not null enforcement, and populate it with different values
  • use mssql_login run CreateSession=true ... to get a session
  • sessions -i -1
  • run queries against this table in both sqlcmd in your mssql instance and via your msf mssql client, verify that the output is the same and there are no unknown column type errors with values 50 or 104.

Setting up MSSQL Table

in your mssql instance, run the following steps:

  • create table your_table (nullable_bit bit);
  • grant select on your_table to public;
  • alter table your_table add strict_bit bit not null default 0;
  • insert into your_table (nullable_bit, strict_bit) values (0, 0);
  • insert into your_table (nullable_bit, strict_bit) values (0, 1);
  • insert into your_table (nullable_bit, strict_bit) values (1, 0);
  • insert into your_table (nullable_bit, strict_bit) values (1, 1);
  • insert into your_table (nullable_bit, strict_bit) values (NULL, 0);
  • insert into your_table (nullable_bit, strict_bit) values (NULL, 1);

previously, running select * from your_table; would break this if run from your mssql client in metasploit framework. This now should look like:

msf6 auxiliary(scanner/mssql/mssql_login) > sessions -i -1
[*] Starting interaction with 1...

MSSQL @ 192.168.2.227:1433 (master) > query "select * from your_table;"

[*] 192.168.2.227:1433    - SQL Query: select * from your_table;
[*] 192.168.2.227:1433    - Row Count: 6 (Status: 16 Command: 193)
Response
========

 nullable_bit  strict_bit
 ------------  ----------
 0             0
 0             1
 1             0
 1             1
 NULL          0
 NULL          1

or from modules:

msf6 auxiliary(admin/mssql/mssql_sql) > run SESSION=2 SQL="select * from your_table;"

[*] Using existing session 2
[*] 192.168.2.227:1433    - SQL Query: select * from your_table;
[*] 192.168.2.227:1433    - Row Count: 6 (Status: 16 Command: 193)
Response
========

 nullable_bit  strict_bit
 ------------  ----------
 0             0
 0             1
 1             0
 1             1
 NULL          0
 NULL          1

@adfoster-r7
Copy link
Contributor

Verification

run queries against this table in both sqlcmd in your mssql instance and via your msf mssql client, verify that the output is the same and there are no unknown column type errors with values 50 or 104.

Just to help with testing - would you mind sharing those queries, or sharing the SQL for creating new tables and values that replicate this issue 👍

@zgoldman-r7
Copy link
Contributor Author

Verification

run queries against this table in both sqlcmd in your mssql instance and via your msf mssql client, verify that the output is the same and there are no unknown column type errors with values 50 or 104.

Just to help with testing - would you mind sharing those queries, or sharing the SQL for creating new tables and values that replicate this issue 👍

I'll edit the steps now!

@@ -178,6 +178,13 @@ def mssql_parse_tds_reply(data, info)
col[:id] = :int
col[:int_size] = data.slice!(0, 1).unpack('C')[0]

when 50
col[:id] = :sybbit
Copy link
Contributor

@adfoster-r7 adfoster-r7 Feb 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does sybbit come from? 👀

Is that this?

BITTYPE          =   %x32  ; Bit 

https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/859eb3d2-80d3-40f6-a637-414552c9c552
 BITNTYPE            =   %x68

https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/ce3183a6-9d89-47e8-a02f-de5a1a1303de

Copy link
Contributor

@adfoster-r7 adfoster-r7 Feb 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, is the existing implementation and terminology from freetds rather than the microsoft tds spec?

0x32	50	SYBBIT		no	0

...

0x68	104	SYBBITN		yes	1

https://www.freetds.org/tds.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got bitntype from the microsoft tds spec and sybbit from the freetds spec - I'm open to feedback on the names. I think it would be reasonable to change to both of the freetds names, or :bit and :nullable_bit to be more specific?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah; From what I understand, in freetds - syb is just a prefix that C developers use, and it comes from the sybase product as far as I can see:

TDS Version Supported Products
4.2 Sybase SQL Server < 10 and Microsoft SQL Server 6.5
5.0 Sybase SQL Server >= 10
7.0 Microsoft SQL Server 7.0
7.1 Microsoft SQL Server 2000
7.2 Microsoft SQL Server 2005

So the naming convention should just probably be:

SYBBIT => bit
SYBBITN => bitn

when :bitntype
has_value = data.slice!(0, 1).unpack("C")[0]
if has_value == 0
row << 'NULL'
Copy link
Contributor

@adfoster-r7 adfoster-r7 Feb 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be row << nil ? 👀

The rationale being, the string 'NULL' is definitely not the same as an actual Ruby nil

If you want it to appear as NULL in the table outputs of modules, you'll have to handle that in your presentation layer - not here 👍

col[:id] = :sybbit

when 104
col[:id] = :bitntype
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
col[:id] = :bitntype
col[:id] = :bitn

@@ -178,6 +178,13 @@ def mssql_parse_tds_reply(data, info)
col[:id] = :int
col[:int_size] = data.slice!(0, 1).unpack('C')[0]

when 50
col[:id] = :sybbit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
col[:id] = :sybbit
col[:id] = :bit

row << data.slice!(0, 1).unpack("C")[0]
end

when :sybbit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
when :sybbit
when :bit

@@ -292,6 +299,17 @@ def mssql_parse_tds_row(data, info)
when :tinyint
row << data.slice!(0, 1).unpack("C")[0]

when :bitntype
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
when :bitntype
when :bitn

@adfoster-r7 adfoster-r7 merged commit 787a2cb into rapid7:master Feb 26, 2024
34 checks passed
@adfoster-r7 adfoster-r7 added the rn-enhancement release notes enhancement label Feb 26, 2024
@adfoster-r7
Copy link
Contributor

Release Notes

Updates the MSSQL modules to support querying database rows that contain boolean bit values

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rn-enhancement release notes enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants