import socket
import os
import time
import re
import urllib
import select
BACKLOG = 100
epoll = select.epoll()
class MainServer :
def __init__(self):
svrsock = 0;
os.chdir("/home/ohhyunkyu/httpd")
self.conn = 0;
def ServerRun (self):
svrsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
svrsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# socket bind
svrsock.bind(('192.168.201.120',80))
svrsock.listen(BACKLOG)
# epoll socket add
epoll.register(svrsock.fileno(),select.EPOLLIN)
# Connection array
connections = {}
self.responses = {}
while True :
# event listener
events = epoll.poll(1)
for fileno, event in events :
if fileno == svrsock.fileno() :
self.conn , (remhost,remport) = svrsock.accept()
self.conn.setblocking(0)
epoll.register(self.conn.fileno(),select.EPOLLIN)
connections[self.conn.fileno()] = self.conn
self.responses[self.conn.fileno()] = ''
elif event & select.EPOLLIN :
readText = connections[fileno].recv(1024)
if len(readText) > 1 :
self.ParsingText(fileno,readText)
elif event & select.EPOLLOUT :
connections[fileno].send(self.responses[fileno])
epoll.unregister(fileno)
connections[fileno].close()
def ParsingText(self,fileno,readText) :
contentLine = str(readText).splitlines()
type = str(contentLine[0]).split(" ")[0]
path = str(contentLine[0]).split(" ")[1]
version = str(contentLine[0]).split(" ")[2]
if str(type).upper() == "GET" :
if path == "/" :
path += "main.html"
# Rule inject
if self.UploadFolderCheck(path) == -1 :
epoll.modify(fileno, select.EPOLLOUT)
self.responses[fileno] = "HTTP 403 Forbidden\r\nContent-Length: 13\r\n\r\n <h1>Forbidden"
return 0
if self.existsFileCheck(path) == -1 :
epoll.modify(fileno, select.EPOLLOUT)
self.responses[fileno] = "HTTP 404 OK\r\nContent-Length: 14\r\n\r\n<h1> Not Found"
return 0
if self.getParamCheck(fileno,path) == -1 :
epoll.modify(fileno, select.EPOLLOUT)
#self.responses[fileno] = "HTTP 400 Bad Request\r\nContent-Length: 15\r\n\r\n<h1>Bad Request"
return 0
responseAddr = str(path)[1:]
if responseAddr.find("?") > 0 :
fName = responseAddr[:responseAddr.find("?")] # request File Name Parsing
Param = responseAddr[responseAddr.find("?")+1:] # request Parameter Parsing
Content = self.CallPageMake(fName, Param) # response Page Make
epoll.modify(fileno, select.EPOLLOUT)
self.responses[fileno] = Content
else :
epoll.modify(fileno, select.EPOLLOUT)
self.responses[fileno] = self.Response(responseAddr)
elif str(type).upper() == "POST" :
BodyContent = str(readText)[str(readText).find("\r\n\r\n"):] # BydyContent Parsing
BodyContent = self.replaceBodyContent(BodyContent) # Decoding
if self.UploadFolderCheck(path) == -1 :
epoll.modify(fileno, select.EPOLLOUT)
self.responses[fileno] = "HTTP 403 Forbidden\r\nContent-Length: 13\r\n\r\n <h1>Forbidden"
return 0
if self.existsFileCheck(path) == -1 :
epoll.modify(fileno, select.EPOLLOUT)
self.responses[fileno] = "HTTP 404 OK\r\nContent-Length: 14\r\n\r\n<h1> Not Found"
return 0
def PostMethodCheck(self,readText,DirPath,BodyContent) :
if self.QueryCheck(DirPath, BodyContent) :
return 0
else :
return -1
# common GET / POST Check Method
def UploadFolderCheck(self,path):
DirPath = str(path)
FolderAddr = DirPath[:DirPath.rfind("/")]
FileExt = DirPath[DirPath.rfind("."):]
spritFolders = FolderAddr.split("/")
i=0
while i < len(spritFolders) :
if len(spritFolders)-1 == i : # Last Folder = Upload
if str(FileExt) == ".asp" or str(FileExt) == ".exe" : # Execute File Ext .asp or .exe
return -1
i = i +1
return 0
def existsFileCheck(self,DirPath):
if str(DirPath).find("?") > 0 : # Param Ext
Path = str(DirPath).split("?")[0][1:]
if os.path.exists(str(Path)) == True :
return 0
else :
return -1
else :
if os.path.exists(str(DirPath)[1:]) == True :
return 0
else :
return -1
# GET Request Parameter Check
def getParamCheck(self,fileno,path):
path = self.replaceBodyContent(path)
if str(path).find("&") > 0 :
BodyContent = path[path.find("?")+1:]
BodyContent = self.replaceBodyContent(BodyContent)
queryList = str(BodyContent).split("&")
i = 0
while i < len(queryList) : # Query Check
if self.QueryCheck(fileno,path, queryList[i]) :
i=i+1
else :
return -1
return 0
else : # if Param Count = 1
tmp = str(path)
BodyContent = tmp[tmp.find("?")+1:]
BodyContent = self.replaceBodyContent(BodyContent)
if self.QueryCheck(fileno,path, BodyContent) :
return 0
else :
return -1
def replaceBodyContent(self,BodyContent):
BodyContent = BodyContent.replace('%3C','<')
BodyContent = BodyContent.replace('%3E','>')
BodyContent = BodyContent.replace("%2F", "/")
BodyContent = BodyContent.replace("%7C","|")
BodyContent = BodyContent.replace("%27", "'")
BodyContent = BodyContent.replace("%28", "(")
BodyContent = BodyContent.replace("%29", ")")
BodyContent = BodyContent.replace("+", " ")
BodyContent = BodyContent.replace("%2B", "+")
BodyContent = BodyContent.replace("%E2","\'")
BodyContent = BodyContent.replace("%22","\"")
BodyContent = BodyContent.replace("%25","%")
BodyContent = BodyContent.replace("%3D","=")
BodyContent = BodyContent.replace("%5B","[")
BodyContent = BodyContent.replace("%5D","]")
BodyContent = BodyContent.replace("%3F","?")
BodyContent = BodyContent.replace("%40", "@")
BodyContent = BodyContent.replace("%26", "&")
return BodyContent
def QueryCheck(self,fileno,DirPath,BodyContent) :
# ref page : http://codeflow.co.kr/question/1061/
pattern = re.search('<.*?>',BodyContent)
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
pattern = re.search('location[\=\s\w\%d]*http',BodyContent,re.IGNORECASE)
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath, Content)
return False
# pattern is %00 ' and sql injection
pattern = re.search('%00?[\'\s]+\w*',BodyContent,re.IGNORECASE)
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is select @@version
pattern = re.search('select[\s]*[%\d]*@@version',BodyContent,re.IGNORECASE)
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is Group by having injection
pattern = re.search('group[\s]*[%\d]*by[\s]*[%\d]*[\w]*[\s]having',BodyContent,re.IGNORECASE)
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is parameter parsing and 'or find it.
pattern = re.search('[\'\s\)\(]*or[\'\s\"\)\(]*\w*=[\'\s\"]*\w*[\'\s\"]*',BodyContent,re.IGNORECASE)
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is parameter parsing and find it.
pattern = re.search('[\'\s]*and[\[\s]*[\w\s]*[\]\s]?[\w\s]*and',BodyContent,re.IGNORECASE)
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is 'sel'||'ect' or 'sel'+'ect' || 'sel' 'ect'
pattern = re.search('\w*[\'\"][\|\"\'\+\s]*[\'\"]\w*',BodyContent,re.IGNORECASE) # "SEL\" \"ECT" ..
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
#Cscript%3Etest%3C%2Fscript%3E # pattern is char(85) or chr(85) ...
pattern = re.search('char[\( \s]*[0-9]*[\)\s]*',BodyContent,re.IGNORECASE) # char(85) test ..
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is select * from table where < - full operation find it.
pattern = re.search('select[%\d\s]*\w*[\s]*from',BodyContent,re.IGNORECASE) # select * from table where
# where line - > [%\d\s]*\w*[\s]*where
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is union ~~ from < - full operation find it
pattern = re.search('union[%\d\s]*\w*[%\d\s]*\w*[%\d\s]*from',BodyContent,re.IGNORECASE) # union select * from
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
# pattern is insert into( ) values < -- full operation find it
pattern = re.search('insert[%\d\s]into[%\d\s\w \( \)]* values',BodyContent,re.IGNORECASE) # insert into values
if pattern :
Content = pattern.group()
self.ErroSqlexecute(fileno,DirPath,Content)
return False
return True
def logWriter(self,path,type,content):
f = open("WebServerLog.log",'a')
peerAddress = str(self.conn.getpeername())
nowTmp = time.localtime()
now = "%02d-%02d-%02d %02d:%02d:%02d" % (nowTmp.tm_year, nowTmp.tm_mon, nowTmp.tm_mday , nowTmp.tm_hour , nowTmp.tm_min, nowTmp.tm_sec)
Path = str(path)
LogContent ="Time=" + now + " Path=" + Path + " Connect=" + peerAddress
if type == 404 : # File Not Found
LogContent += " Event=File Not Found\r\n"
elif type == 400 : # Big Param , ' - Param
LogContent += " Event=Bad Request \r\n"
elif type == 403 : # WebShell
LogContent += " Event=Warning Extention \r\n"
elif type == 50 : # Post Content Script
LogContent += " Event=Body Content Script \r\n"
elif type == 100 :
LogContent += " Event= Sql Injection : "+ content + "\r\n"
else :
LogContent += " Event=NULL Event \r\n"
f.write(LogContent)
f.close();
def CallPageMake(self,path,Param) :
path = str(path)
f=open(path,'r+')
tmp = f.readlines()
writetmp=""
for line in tmp:
if str(line).find("<t1") > 1 :
writetmp+=line
writetmp+="<br>"+ Param
else :
writetmp+=line
f.seek(0,0)
f.write(writetmp)
f.close();
if path.find(".ohk") > 0 :
os.system("cp mresult.ohk result.ohk")
else :
os.system("cp mresult.html result.html")
return writetmp
def Response(self,File):
files = open(File, 'r')
lines = files.readlines()
FileLen = os.path.getsize(str(File))
nowTmp = time.asctime()
tmp = nowTmp.split()
timeString = tmp[0] + ", " + tmp[2] +" "+tmp[1]+ " "+tmp[4] + " "+tmp[3] + " GMT"
SendFileHeader = "HTTP/1.1 200 OK \r\nDate: "+timeString+"\r\nExpires:" +timeString +"\r\nCache-Control: no-store,no-cache,must-revalidate\r\nContent-Length: "+str(FileLen)+"\r\nConnection: close\r\nContent-Type : text/html\r\n\r\n"
#self.conn.sendall(SendFileHeader)
for line in lines:
#encoding = self.replaceBodyContent(str(line))
encoding = str(line)
SendFileHeader+=encoding
files.close()
return SendFileHeader
def ErroSqlexecute(self,fileno,DirPath,Content):
lens = len(Content)+24
ERRORMESSAGE = "HTTP 400 Bad Request\r\nContent-Length:"+str(lens)+" \r\n\r\n <h1>SQL Syntax Error : "+Content
self.responses[fileno] = ERRORMESSAGE
epoll.modify(fileno, select.EPOLLOUT)
self.logWriter(DirPath, 100,Content)
class ServerStart :
acceptor = MainServer()
acceptor.ServerRun()
'[학교] 시스템 보안 > Python' 카테고리의 다른 글
Pipe 사용 예제 (0) | 2014.04.10 |
---|---|
쓰레드를 활용한 웹 서버 (0) | 2013.12.26 |
멀티 IO / SubProc 활용한 웹 서버 (0) | 2013.12.26 |
라이브러리 활용 예제 (0) | 2013.12.26 |