Aquaboutic | Focus Security Research | Vulnerability Exploit | POC


several small tricks to attack lnmp architecture web application

Posted by barkins at 2020-02-25

On the first day of the lunar new year, I shared a red envelope on the code audit knowledge planet, but the condition for receiving the red envelope is to solve a code audit related problem I gave. The main task is as follows:

0x01 pull source code

The problem is relatively simple. We open it with a browser and find the prompt err  invalid  http  response, indicating that this port is not an HTTP service. Nmap is used for port fingerprint identification


It can be seen that this is an Rsync service. We use the Rsync command to view the directory and find that there is only one directory, named pwnhub_.git. Pull it down:


Check the pwnhub_.git directory and find that this is a git bare repository.


How to restore git bare warehouse? In fact, it's very simple. All the warehouses we usually use on GitHub and gitlab are actually naked warehouses. For example, we pull the source code of vulhub and execute git clone, where vulhub.git is actually a naked warehouse on GitHub server. It can be seen that the bare warehouse is generally named "project name. Git".

git clone vulhub.git

Git supports pulling information through local files, SSH, HTTPS, or git protocols. Since we have used Rsync to download the bare warehouse to the local, we only need git clone pwnhub_.git to pull the bare warehouse down and become a standard warehouse:

git clone pwnhub_6670.git

The content in the pwnhub folder of the warehouse is the source code we need to audit.


0x02 SQL injection vulnerability mining

As a problem maker, I played a little bit of a trick. I used a small PHP framework called speed, but changed the core file name to core.php. In order to prevent everyone from looking for the vulnerability of the framework itself and leading to the deviation, all the vulnerable codes are in the code I wrote.


To get the source warehouse, the first step is to look at git log, branch, tags and other information, which may reveal some sensitive information of the target. Not here, so we should target the code itself.

git log

The target website only has simple registration and login functions. The code for entry is as follows:

Escape is to convert single quotation marks and parentheses in GPR into Chinese symbols and escape them with backslashes; arg is to obtain $_requestor $_serverentered by the user. Obviously, the $_servervariable has not been escaped here. Note this first.


There's nothing else to notice globally, so start looking at the controller's code.

The above is the code of registration function, which is relatively simple. User name and password are required. If the email is not filled in, it will be automatically set to "user name @ website domain name". Finally, the three are passed into the Create method. The Create method is actually splicing an INSERT statement.

It is worth noting that the website domain name is obtained from Arg ('http_host '), that is, from $_requestor $_server. Because $_serveris not escaped, we only need to introduce a single quotation mark in the HTTP header host value to create a SQL injection vulnerability.


However, the email variable has been detected by filter ﹐ var ($email, filter ﹐ valid ﹐ email). We need to bypass it first.

filter_var($email, FILTER_VALIDATE_EMAIL)


FILTER_VALIDATE_EMAIL \ Joe\'[email protected] "Joe'Blow"

Although PHP is not fully tested in accordance with RFC 3696, it supports the second writing method mentioned above. Therefore, we can use it to bypass filter "validate" email detection.


Because the mailbox in the code is a combination of user name, @, and host, but the user name is escaped, the single quotation mark can only be placed in the host. We can pass in the user name as "AAA '" @, and the final splicing email is "@ AAA'" @

" aaa'" "@aaa'"

This email is legal:

This mailbox contains single quotes, which will close the original single quotes in the SQL statement, causing SQL injection vulnerability.

0x04 bypass nginx host limit

This is the second trick today.

We try to send the user name and host just constructed to the target registration page:

404 is displayed directly, which does not seem to enter the PHP process.

This goes back to the essence of the problem. What does the host header do?

As we all know, if we input into the browser, the browser will first request the DNS server to obtain the IP address of the target server, and then the TCP communication will have nothing to do with the domain name. So, if there are multiple websites on a server, how will nginx distinguish them after receiving HTTP packets?

This is what the host does: it is used to distinguish which website the user visits (in nginx, the server block).

If nginx finds that the host we passed in cannot find the corresponding server block, it will send it to the default server block, that is, the default page of nginx that we directly access through the IP address:

The default website does not have the processing method of the request / main / register, so it will naturally return 404.


Here are two ways to solve this problem. Maybe there are more new ways I didn't expect. Welcome to add.

Law 1

When nginx processes the host, it will use colons to divide the host into hostname and port, and the port part will be discarded. Therefore, we can set the host value to 2018. MHz. PW: xxx '"@ example. Com, so we can access the target server block:'"

As shown in the figure above, the SQL error is triggered successfully.

Law 2

When we pass in two host headers, nginx will take the first one, and php-fpm will take the second one.

In other words, if I introduce:

Nginx will assume that the host is and submit it to the target server block for processing; however, the value obtained by using $_server ['http_host '] in PHP is xxx' "@ example. Com. This also bypasses: $_SERVER['HTTP_HOST'] xxx'"

I mentioned this method in a group before. Only nginx + PHP will cause this problem. Apache will be another way. We will not discuss it here.

0x05 Mysql 5.7 INSERT method

This is the third trick today.

Since SQL error has been triggered, SQL injection is near at hand. By reading the SQL structure contained in the source code, we know that the flag is in the flags table, so we can directly inject and read the table without nonsense.

Insert display bit

Since the user's email address will be displayed after successful login, we can insert data into this location. Send the following packets:

As you can see, I closed the insert statement, inserted a new user T123, and read the flag into the email field. Log in to the user and get the flag:


Flag is Alipay's red envelope password. )

Error injection

In order to reduce the difficulty, I specially gave the error reporting information of MySQL. Unexpectedly, it increased the difficulty. I didn't take this into account. It was the solution proposed by @ burnegg.

Many students come up to test and report error injection, but there are two pits to bypass:

ErrorInfo: Truncated incorrect INTEGER value

Instead of using string connection syntax, we can use comparison symbols such as <, >, = to trigger the vulnerability:

< > =

For more information about insert injection, please read MySQL injection in update, insert and delete.

0x06 a summary

When the title came out, more than a thousand students took part in it. The fastest way to get Alipay's red envelope was @ Chao Wei blue cat, probably at 1 a.m. in the second day of the morning.

In addition to the security researchers, some programmers also participated in the game, but because they are not familiar with CTF competitions and security related loopholes, some people deviated and did not focus on loopholes and security technology itself, but to guess whether the red packet password is hidden in the picture or other places.

I hope this game will bring you not only the joy of the new year, but also the improvement of technology~