Skip to content

Fix command injection on PDB download #16966

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

Merged
merged 16 commits into from
Jun 10, 2020

Conversation

GustavoLCR
Copy link
Contributor

@GustavoLCR GustavoLCR commented May 29, 2020

Your checklist for this pull request

  • I've read the guidelines for contributing to this repository
  • I made sure to follow the project's coding style
  • I've added tests that prove my fix is effective or that my feature works (if possible)
  • I've updated the documentation and the radare2 book with the relevant information (if needed)

Detailed description

Reported in #16945, this fixes specifically the vulnerability while downloading a PDB by avoiding calling curl through a command and using radare2's own http request API, and in case of downloads from https servers with no SSL suport from the r2 api or when extracting compressed PDBs, properly escaping the PDB name with single-quotes (double-quotes on Windows).

This includes fixes to compiling radare2 with SSL support (--with-openssl), and fixes the handshake process not being executed while connecting with SSL.

Also, now r_socket_http_get() will follow redirects automatically.

Test plan

  • Compile with --with-openssl
    • Try to download a pdb with idpd (works)
  • Compile without --with-openssl
    • Try to download a pdb with idpd (fails because no SSL support)
    • Set %R2_CURL=1
    • Try to download a pdb with idpd (works)
  • Download the binary from Command injection across r_sys_cmd* #16945, open and do idpd, pwned file should not get created
  • Do =h to run httpserver and in another terminal, connect to it.

@GustavoLCR GustavoLCR changed the title Fix pdb cmd inj Fix command injection on PDB download May 29, 2020
@github-actions github-actions bot added the RBin label May 29, 2020
@XVilka
Copy link
Contributor

XVilka commented May 29, 2020

Seems to fail more often:
https://builds.sr.ht/~xvilka/job/221987#task-test-0

[XX] db/formats/pdb PDB downloader check
R2_NOPLUGINS=1 radare2 -escr.utf8=0 -escr.color=0 -escr.interactive=0 -N -Qc '!!rabin2 -PP ${R2_FILE} ~PDB' bins/pdb/user32.dll
-- stdout
--- .a	2020-05-29 04:37:20.548603000 +0000
+++ .b	2020-05-29 04:37:20.548687000 +0000
@@ -1 +1 @@
-PDB "user32.pdb" download success
+PDB "user32.pdb" download failed

https://github.com/radareorg/radare2/pull/16966/checks?check_run_id=719199580#step:11:130

[XX] db/formats/pdb PDB downloader check
R2_NOPLUGINS=1 radare2 -escr.utf8=0 -escr.color=0 -escr.interactive=0 -N -Qc '!!rabin2 -PP ${R2_FILE} ~PDB' bins/pdb/user32.dll
-- stdout

Copy link
Contributor

@ret2libc ret2libc left a comment

Choose a reason for hiding this comment

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

Do you have some reproducer steps to test the various things you fixed?

@GustavoLCR GustavoLCR force-pushed the fix-pdb-cmd-inj branch 7 times, most recently from 933f615 to 2184566 Compare May 31, 2020 07:48
@GustavoLCR
Copy link
Contributor Author

Do you have some reproducer steps to test the various things you fixed?

@ret2libc updated pr description with test steps.

Also, newshell is failing this:
%R2_CURL=1;idpd
But this works
%R2_CURL=1 ;idpd

@GustavoLCR GustavoLCR force-pushed the fix-pdb-cmd-inj branch 4 times, most recently from 588ce77 to 1bb5d69 Compare May 31, 2020 22:00
@ret2libc
Copy link
Contributor

ret2libc commented Jun 1, 2020

Do you have some reproducer steps to test the various things you fixed?

@ret2libc updated pr description with test steps.

Also, newshell is failing this:
%R2_CURL=1;idpd
But this works
%R2_CURL=1 ;idpd

Thanks for reporting this, it should be fixed with #16988 .

@github-actions github-actions bot added the API New API requests, changes, removal label Jun 2, 2020
@GustavoLCR GustavoLCR force-pushed the fix-pdb-cmd-inj branch 2 times, most recently from 8840369 to c4e2872 Compare June 2, 2020 03:57
@github-actions github-actions bot added the r2r Regression tests label Jun 4, 2020
Copy link
Contributor

@ret2libc ret2libc left a comment

Choose a reason for hiding this comment

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

Added some more comments, but I think it's almost ready!

@@ -191,6 +151,19 @@ void deinit_pdb_downloader(SPDBDownloader *pd) {
pd->download = 0;
}

static bool is_valid_guid(const char *guid) {
Copy link
Contributor

Choose a reason for hiding this comment

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

GUID are 32 chars long, aren't they? I'm not sure this function works correctly.
e.g.:

is_valid_guid('12345678901234567890123456789012') should be true
is_valid_guid('123456789012345678901234567890123') should be false

I think that currently this function does not return the right values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

tested it, function works correctly

Copy link
Contributor

Choose a reason for hiding this comment

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

Mmm, for me it doesn't. I'm using this test, where is_valid_guid is copied-pasted from your PR.

#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

static bool is_valid_guid(const char *guid) {
	if (!guid) {
		return false;
	}
	size_t i;
	for (i = 0; guid[i] && i <= 33 ; i++) {
		if (!isxdigit (guid[i])) {
			return false;
		}
	}
	return i == 33;
}

static void test_s(const char *s) {
	if (is_valid_guid (s)) {
		printf("'%s' is valid guid\n", s);
	} else {
		printf("'%s' is NOT valid guid\n", s);
	}
}

int main(int argc, char **argv) {
	test_s("12345678901234567890123456789012");
	test_s("123456789012345678901234567890123");
	return 0;
}

If I run this program, it says:

'12345678901234567890123456789012' is NOT valid guid
'123456789012345678901234567890123' is valid guid

but the expected output is:

'12345678901234567890123456789012' is valid guid
'123456789012345678901234567890123' is NOT valid guid

Please let me know if I'm missing something.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

turns out guid string has appended to it the "age", so assuming it even has a fixed length was wrong, fixed it now

Copy link
Contributor

Choose a reason for hiding this comment

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

mh, that looks weird, but it seems it is something a bit more deeper in the existing code. Guid are 32 chars AFAIK. Nevermind.

* Use r_socket_http_get() on UNIXs
* Use WinINet API on Windows for r_socket_http_get()
* Fix command injection
* Remove 'r_' and '__' from static function names
Copy link
Contributor

@ret2libc ret2libc left a comment

Choose a reason for hiding this comment

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

Added some last minor stuff + doubts about is_valid_guid. Once is_valid_guid is fixed (or you prove me I'm doing something wrong :D) I think we can merge this. Thanks a lot for all the changes you have done!

Copy link
Collaborator

@trufae trufae left a comment

Choose a reason for hiding this comment

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

Good work! nice to see new escaping APIs, we probably need to have the unescape_sh() one too, and have more tests for them

Copy link
Contributor

@ret2libc ret2libc left a comment

Choose a reason for hiding this comment

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

Looks good, thanks again!

@ret2libc ret2libc merged commit 04edfa8 into radareorg:master Jun 10, 2020
TrustMeIm0xDolphin pushed a commit to TrustMeIm0xDolphin/radare2 that referenced this pull request Jul 12, 2020
* Fix r_sys_mkdirp with absolute path on Windows
* Fix build with --with-openssl
* Use RBuffer in r_socket_http_answer()
* r_socket_http_answer: Fix read for big responses
* Implement r_str_escape_sh()
* Cleanup r_socket_connect() on Windows
* Fix socket being created without a protocol
* Fix socket connect with SSL ##socket
* Use select() in r_socket_ready()
* Fix read failing if received only protocol answer
* Fix double-free
* r_socket_http_get: Fail if req. SSL with no support
* Follow redirects in r_socket_http_answer()
* Fix r_socket_http_get result length with R2_CURL=1
* Also follow redirects
* Avoid using curl for downloading PDBs
* Use r_socket_http_get() on UNIXs
* Use WinINet API on Windows for r_socket_http_get()
* Fix command injection
* Fix r_sys_cmd_str_full output for binary data
* Validate GUID on PDB download
* Pass depth to socket_http_get_recursive()
* Remove 'r_' and '__' from static function names
* Fix is_valid_guid
* Fix for comments
@GustavoLCR GustavoLCR deleted the fix-pdb-cmd-inj branch October 14, 2020 03:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API New API requests, changes, removal r2r Regression tests RBin
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants