Created attachment 186080 [details] Reverse shell via remote code execution Hi team, I’ve discovered a security vulnerability in the latest version of Koha. This issue allows an authenticated administrator to achieve remote code execution on the underlying host via code injection. The user-supplied input in the 'Babeltheque_url_update' field within the preferences is passed without sanitisation to 'system( qq{/usr/bin/wget $url -O $output_dir/social_data.csv.bz2 } ) == 0 or die "Can't get bz2 file from url $url ($?)";'. If a cron job has been scheduled or the user runs the 'update_social_data.pl' script, the injected code is executed. An example payload of '$(whoami > /tmp/rce.txt)' can be used to demonstrate the execution of code. Consequently, an attacker can insert malicious code that is executed when the associated script runs. In the example screenshot I have provided, this led to code execution under the Koha account, allowing compromise of the server.
Created attachment 186082 [details] [review] Bug 40748: Fix RCE in update_social_data.pl This patch fixes an identified RCE in the update_social_data.pl social_data, which when executed, allows an attacker to run arbitrary code on the system's shell. TO TEST: a) In the Babeltheque_url_update syspref, wrap any bash in $(), and then run the update_social_data.pl script. *) For example, $(whoami > /tmp/rce.log) will output to a file the username the perl script is running as. APPLY PATCH b) Run the update_social_data.pl script again. The string is now meta-escaped, and the RCE no longer works.
Jake's patch does work, but I'm not quite comfortable with it. -- The quotemeta does quote the metacharacters which prevents the RCE via the $(whoami > /tmp/rce.log) payload, so that's good. It also quotes the metacharacters used in a valid URL: http\:\/\/localhost\:8080\/\?a\=b\&c\=d Yet, wget still works, so that's good. But it got me thinking... it still works because the input is still being interpreted via the shell. If for some reason someone eventually removed the quotemeta or quotemeta itself changed, we'd be back to square one... I'm going to suggest two things. One: we do some data checks to see if we're getting a HTTP URL. Two: we skip the shell all together by using the "system PROGRAM LIST" syntax.
Created attachment 186111 [details] [review] Bug 40748: Check for HTTP URLs and skip shell when using system() This change checks for HTTP(S) URLs and skips the shell when using system() so that shell metacharacters aren't interpreted. Test plan: 0. Apply the patch 1. Insert the following into the Babeltheque_url_update system preference: $(whoami > /tmp/rce.log) 2. koha-shell kohadev 3. perl misc/cronjobs/social_data/update_social_data.pl 4. Note the script says the following: $(whoami > /tmp/rce.log) is not a HTTP URL. Aborting. 5. Note also that /tmp/rce.log is not created 6. Change Babeltheque_url_update syspref to something like the following: http://localhost:8080 7. perl misc/cronjobs/social_data/update_social_data.pl 8. Note that the wget succeeds but the bunzip2 fails (as expected) since we haven't fetched a bzipped file 9. Try to create a payload that passes the HTTP URL test with shell metacharacters and note that they're not interpetted and instead just used as part of a URL string.
Hi David, Thanks for the patch, looks grand to me! I must admit, I was tossing and turning in my sleep last night thinking this patch of mine is ugly and probably breaks wget. Top job for getting a better patch in so quickly! It is greatly appreciated. Ta, Jake
Created attachment 186114 [details] [review] Bug 40748: Check for HTTP URLs and skip shell when using system() This change checks for HTTP(S) URLs and skips the shell when using system() so that shell metacharacters aren't interpreted. Test plan: 0. Apply the patch 1. Insert the following into the Babeltheque_url_update system preference: $(whoami > /tmp/rce.log) 2. koha-shell kohadev 3. perl misc/cronjobs/social_data/update_social_data.pl 4. Note the script says the following: $(whoami > /tmp/rce.log) is not a HTTP URL. Aborting. 5. Note also that /tmp/rce.log is not created 6. Change Babeltheque_url_update syspref to something like the following: http://localhost:8080 7. perl misc/cronjobs/social_data/update_social_data.pl 8. Note that the wget succeeds but the bunzip2 fails (as expected) since we haven't fetched a bzipped file 9. Try to create a payload that passes the HTTP URL test with shell metacharacters and note that they're not interpetted and instead just used as part of a URL string. Signed-off-by: Jake Deery <jake.deery@openfifth.co.uk>
Created attachment 186116 [details] [review] Bug 40748: Fix RCE in update_social_data.pl This patch fixes an identified RCE in the update_social_data.pl social_data, which when executed, allows an attacker to run arbitrary code on the system's shell. TO TEST: a) In the Babeltheque_url_update syspref, wrap any bash in $(), and then run the update_social_data.pl script. *) For example, $(whoami > /tmp/rce.log) will output to a file the username the perl script is running as. APPLY PATCH b) Run the update_social_data.pl script again. The string is now meta-escaped, and the RCE no longer works. Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Created attachment 186117 [details] [review] Bug 40748: Check for HTTP URLs and skip shell when using system() This change checks for HTTP(S) URLs and skips the shell when using system() so that shell metacharacters aren't interpreted. Test plan: 0. Apply the patch 1. Insert the following into the Babeltheque_url_update system preference: $(whoami > /tmp/rce.log) 2. koha-shell kohadev 3. perl misc/cronjobs/social_data/update_social_data.pl 4. Note the script says the following: $(whoami > /tmp/rce.log) is not a HTTP URL. Aborting. 5. Note also that /tmp/rce.log is not created 6. Change Babeltheque_url_update syspref to something like the following: http://localhost:8080 7. perl misc/cronjobs/social_data/update_social_data.pl 8. Note that the wget succeeds but the bunzip2 fails (as expected) since we haven't fetched a bzipped file 9. Try to create a payload that passes the HTTP URL test with shell metacharacters and note that they're not interpetted and instead just used as part of a URL string. Signed-off-by: Jake Deery <jake.deery@openfifth.co.uk> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Exiting with an error code would be good if the syspref does not contain a valid URI.
Nice teamwork there, thanks all.
(In reply to Jonathan Druart from comment #8) > Exiting with an error code would be good if the syspref does not contain a > valid URI. Mmm that's true. Good call.
Hi all, The fix looks sufficient to me. The list form of system seems to block the command injection. I have requested a CVE ID for this. Happy to re-test this issue more if required.
(In reply to oos3c from comment #11) > The fix looks sufficient to me. The list form of system seems to block the > command injection. Thanks for that. > I have requested a CVE ID for this. Happy to re-test this issue more if > required. Usually we ask that you wait to request the CVE until after we've pushed the fix out to all supported versions, but it sounds like you've already gone ahead. Could you share that CVE ID number here for our reference? Thanks!
> Usually we ask that you wait to request the CVE until after we've pushed the > fix out to all supported versions, but it sounds like you've already gone > ahead. > > Could you share that CVE ID number here for our reference? Apologies, I will make a note of that for future submissions. An ID hasn't been assigned yet but I will share when I receive more information.
Pushed to 24.11.x-security for 24.11.09
Pushed to 22.11.x-security for 22.11.31
Created attachment 186924 [details] [review] Bug 40748: [24.05.x] Fix RCE in update_social_data.pl This patch fixes an identified RCE in the update_social_data.pl social_data, which when executed, allows an attacker to run arbitrary code on the system's shell. TO TEST: a) In the Babeltheque_url_update syspref, wrap any bash in $(), and then run the update_social_data.pl script. *) For example, $(whoami > /tmp/rce.log) will output to a file the username the perl script is running as. APPLY PATCH b) Run the update_social_data.pl script again. The string is now meta-escaped, and the RCE no longer works. Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org> Bug 40748: Check for HTTP URLs and skip shell when using system() This change checks for HTTP(S) URLs and skips the shell when using system() so that shell metacharacters aren't interpreted. Test plan: 0. Apply the patch 1. Insert the following into the Babeltheque_url_update system preference: $(whoami > /tmp/rce.log) 2. koha-shell kohadev 3. perl misc/cronjobs/social_data/update_social_data.pl 4. Note the script says the following: $(whoami > /tmp/rce.log) is not a HTTP URL. Aborting. 5. Note also that /tmp/rce.log is not created 6. Change Babeltheque_url_update syspref to something like the following: http://localhost:8080 7. perl misc/cronjobs/social_data/update_social_data.pl 8. Note that the wget succeeds but the bunzip2 fails (as expected) since we haven't fetched a bzipped file 9. Try to create a payload that passes the HTTP URL test with shell metacharacters and note that they're not interpetted and instead just used as part of a URL string. Signed-off-by: Jake Deery <jake.deery@openfifth.co.uk> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Security bug fix, no change to the manual required.