Preface
This article fully and thoroughly reproduces every vulnerability case mentioned in the book Code Auditing: Enterprise Web Code Security Architecture and provides the source code packages, so that newcomers who start with this book can reproduce the cases themselves and gain a deeper understanding.
Vulnerability Title
Espcms Search Injection Analysis, p. 73 of the book
Preparations
-
I will not discuss downloading and installing the source code package, or the pitfalls encountered during installation, because they were all mentioned in the previous article reproducing this cms and will not be repeated here
-
Because this vulnerability appears in an older version of espcms, and the espcms vulnerability in the version I currently have has been fixed, we must first modify this cms's vulnerability-related files before we can reproduce the older version's vulnerability. The changes are as follows:
-
First: replace the original code (the code I commented out in the image) of the in_taglist() method in interface/search.php, as marked in the image

- Second: replace the inputcodetrim() function in public/class_function.php with the following code:
function inputcodetrim($str) {
if (empty($str)) return $str;
$str = str_replace("&", "&", $str);
$str = str_replace(">", ">", $str);
$str = str_replace("<", "<", $str);
$str = str_replace("<", "<", $str);
$str = str_ireplace("select", "", $str);
$str = str_ireplace("join", "", $str);
$str = str_ireplace("union", "", $str);
$str = str_ireplace("where", "", $str);
$str = str_ireplace("insert", "", $str);
$str = str_ireplace("delete", "", $str);
$str = str_ireplace("update", "", $str);
$str = str_ireplace("like", "", $str);
$str = str_ireplace("drop", "", $str);
$str = str_ireplace("create", "", $str);
$str = str_ireplace("modify", "", $str);
$str = str_ireplace("rename", "", $str);
$str = str_ireplace("count", "", $str);
$str = str_ireplace("from", "", $str);
$str = str_ireplace("group by", "", $str);
$str = str_ireplace("concat", "", $str);
$str = str_ireplace("alter", "", $str);
$str = str_ireplace("cas", "cast", $str);
$str = preg_replace("/<span[^>]+>/i", "<span>", $str);
$str = preg_replace("/<p[^>]+>/i", "<p>", $str);
$str = preg_replace("/<font[^>]+>/i", "<font>", $str);
$str = preg_replace("/width=(\'|\")?[\d%]+(\'|\")?/i", "", $str);
$str = preg_replace("/height=(\'|\")?[\d%]+(\'|\")?/i", "", $str);
$str = preg_replace("'<style[^\f]*?(\/style>)'si", "", $str);
return $str;
}
Getting Started
- The vulnerability is located in the in_taglist() method in the interface/search.php file. Using the old approach, first analyze the method's source code to work out how the method can be invoked and which parameter has the problem, as shown below:

- First, you can see that the method begins by invoking a parent-class method, start_pagetemplate(), and then includes the class_pagebotton.php file. Based on the name and the source code, we can tell that these are probably related to view-template rendering and pagination, so we need not pay too much attention to these two lines. Continue downward

- As shown, lines 213-217 use the accept() method (the accept() method will not be discussed again; earlier vulnerability articles already covered it) to receive three parameters, $page, $lng, and $tagkey. $page and $lng need not concern us; focus on the $tagkey variable. Line 217 uses the urldecode() function to perform url decoding. This is where the problem lies: it means we can use url encoding twice to bypass the earlier filtering of single and double quotation marks by the accept() method. Line 218 uses the inputcodetrim() method to process this variable. Let us examine the source code of this function:

- You can see that this function mainly uses replacement to prevent sql injection. As shown, it can be bypassed with duplicated text, such as ununionion, which becomes union after passing through the inputcodetrim() function. Next, return to the search.php file and continue reading.

- You can see that lines 219-226 mainly concatenate the $db_where variable. We can see that when the $tagkey variable is empty, a callmessage method is executed. Examining its source code shows that it simply returns to a page; that is, when the $tagkey variable is not passed in, the original page is returned, so this need not concern us. Then you can see that the $tagkey variable is concatenated into the $db_where variable. Looking farther down, line 231 concerns the view template and need not concern us. Line 235 shows that the espcms_document table will subsequently be queried. Line 236 executes a db_numrows() method. Examine the source code of this method:

- This method executes an sql statement. Let us try invoking this method. It is in a php file under interface. Earlier vulnerability-reproduction articles already explained how to invoke it, so we invoke it directly here and print the sql statement executed at this point.

- Here we add the code print_r(), then visit this link:
http://localhost/espcms/upload/index.php? page=1&ac=search&at=taglist&tagkey=1. With 1 passed to tagkey, you can see that $dbwhere is

- Therefore, the complete sql statement executed by the db_numrows() method is
select count(*) as num from espcms_document where lng='cn' and isclass=1 and isclass=1 and find_in_set('1',tags)This function queries and returns the number of records matching the WHERE condition. We now know that tagkey is user input. We do not need to consider what thefind_in_set()function means. Let us return to search.php and continue reading:

- You can see the code from lines 238 through 242. After $countnum returns the count, it facilitates calculating the page count. Then line 243 contains another sql statement, and once again concatenates the $dbwhere variable into it. Lines 245-246 invoke a PageSQL method. Examining this method, it also mainly completes the sql statement. Line 247 executes the sql statement. Therefore, up through line 246, we print the complete sql statement and take a look, as shown below:

- Visit this url:
http://localhost/espcms/upload/index.php? page=1&ac=search&at=taglist&tagkey=1

- Farther down, the data is rendered into the template and returned to the user. Our exploitation point is therefore very clear: use the user-controllable tagkey
parameter with double url encoding to bypass the accept() method's filtering of single and double quotation marks, then use duplicated text to bypass the inputcodetrim()
function. Because errors are not displayed, blind injection is used. A union query cannot be used because two sql statements are executed before and after it, with different numbers of fields.
Construct the following exp:
localhost/espcms/upload/index.php?page=1&ac=search&at=taglist&tagkey=1%2527,tags) or 1=1 and (seselectlect length(username) ffromrom espcms_admin_member limit 0,1)=5 -- hhahaThis can be used to guess the length of the first username in the user table, and the process can then continue. It will not be covered here