0

I am trying to upload files to a wordpress site using python. So far it looks like I can not use the API with session cookies without an extension. So at this point I am trying to follow along with the following post

Login Wordpress with requests - Python3

Uploading of image to WordPress through Python's requests

Here is what I have so far.

#!/usr/bin/python3
import sys, requests

f = 'test.txt'

user='username'
password='password'
url1='https://example.com/wp-login.php'
url2='https://example.com/wp-admin/media-new.php'

headerauth= {'Cookie':'wordpress_test_cookie=WP Cookie check'}
dataauth = {'log':user, 'pwd':password, 'wp-submit':'Log In'}
dataupload = {'post_id': '0', '_wp_http_referer': '/wp-admin/media-new.php', 'action': 'upload_attachement', 'html-upload': 'Upload'}
image = {'async-upload':('test.txt', open(f, "rb"))}

session1=requests.session()
r1 = session1.post(url1, headers=headerauth, data=dataauth)
print(r1)
r2 = session1.get(url2)
print(r2)
r3 = session1.post(url2, data=dataupload, files=image)
print(r3)

When running this I get the following responses, obviously the last one is of interest.

./upload.py
<Response [200]>
<Response [200]>
<Response [403]>

I have also tried pulling the data fields from Chrome after manually uploading a file, posting directly to async-upload.php with similar results.

Update: The response page I get has the following title.

<title>Something went wrong.</title>
...
<body id="error-page">
    <div class="wp-die-message">The link you followed has expired.</div> 
</body>

I also added the nonce value after digging around the source for the page. This is what I found

<input type="hidden" id="_wpnonce" name="_wpnonce" value="74bdb561c5">

This is what I added.

r2 = session1.get(url2)
test = re.search('value="[0-9a-z]{10}"', r2.text)
nonce = re.search('[0-9a-z]{10}', test.group(0))
nonce = nonce.group(0)
dataupload = {'post_id':'0', '_wp_http_referer':'/wp-admin/media-new.php', '_wpnonce':nonce, 'action':'upload_attachement', 'html-upload':'Upload'}

Still no luck. I also noticed that there is a lack of cookies when compared to my browser based sessions. I am going to assume I am not actually authenticating.

TurboAAA
  • 27
  • 1
  • 10

2 Answers2

0

You may need to add more headers in the request.

The headers can be found in the Network > Headers > Request Headers of the Developer Tools. (Press F12 to toggle it.)

Shradha
  • 2,232
  • 1
  • 14
  • 26
  • I have been digging through that intensively. The only meaningful difference I can find is that there are authentication cookies that do not show up in the sessions cookie jar. Looking at the text output after the login and redirect, I am dumped onto the wp-admin dashboard which would tell me that I authenticated. If I could view the response headers I could further test pulling cookies out and see if that makes a difference. – TurboAAA Sep 25 '20 at 15:27
  • 1
    It appears I am authenticated regardless as I would be bounced back to the login page. I will continue looking at headers as you suggest to see if I can fix the "The link you followed has expired" error. – TurboAAA Sep 25 '20 at 15:42
0

The wrong nonce is being used. To pull the correct nonce use the following and post to async-upload.php. The key is to pull the form _wpnonce from the media-new.php page.

If you don't pull from the form parameters, then you could end up with one of a dozen other nonces.

test = re.search('"multipart_params":.*_wpnonce":"[0-9a-z]+"', r1.text)
nonce = re.search('(?<=_wpnonce":")[0-9a-z]{10}', test.group(0))
nonce = nonce.group(0)

With the full code being

#!/usr/bin/python3
import sys, requests, re

f = 'test.txt'

user='user'
password='password'
url1='https://example.com/wp-login.php'
redirecturl='https://example.com/wp-admin/media-new.php'
url2='https://example.com/wp-admin/async-upload.php'

headerauth= {
        'Cookie':'wordpress_test_cookie=WP Cookie check; ROUTEID=.1',
        'Host':'example.com',
        'Content-Type': 'application/x-www-form-urlencoded'
        }
dataauth = {
        'log':user,
        'pwd':password,
        'wp-submit':'Log In',
        'redirect_to': redirecturl,
        'testcookie': 1
        }
image = {'async-upload':('test.txt', open(f, "rb"))}
testimage = open(f, "rb")

session1=requests.session()
session1.get(url1)
r1 = session1.post(url1, headers=headerauth, data=dataauth)

test = re.search('"multipart_params":.*_wpnonce":"[0-9a-z]+"', r1.text)
nonce = re.search('(?<=_wpnonce":")[0-9a-z]{10}', test.group(0))
nonce = nonce.group(0)

uploadheaders = {
        'Connection': 'keep-alive',
        'Referer': 'https://example.com/wp-admin/upload.php',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'same-origin'
        }
dataupload = {
        'name': 'test.txt',
        'action': 'upload-attachement',
        '_wpnonce': nonce,
        'wpmf_folder': '0',
        }

r2 = session1.post(url2, data=dataupload, headers=uploadheaders, files=image)
TurboAAA
  • 27
  • 1
  • 10