The following vulnerabilities:
* CAN-2005-1916 (insecure tempfile creation and arbitrary command
execution in contrib/scripts/linki.py found by Eric Romang) (local
vuln.)
* other vulnerabilities in user-contributed example scripts:
- insecure tempfile creation in contrib/ekgh, contrib/ekgnv.sh,
contrib/getekg.sh (local vuln.)
- potential shell command injection in contrib/scripts/ekgbot-pre1.py
(if indeed exploitable, a remote vuln.)
found by Marcin Owsiany and Wojtek Kaniewski
Are fixed in:
- upstream version 1.6rc2
- sid package 1:1.5+20050712+1.6rc2-1 (uploaded)
- sarge package 1:1.5+20050411-4 (available at
deb http://people.debian.org/~porridge/ekg-sarge/ ./
interdiff attached
All previous versions are vulnerable (except for some very old ones,
which do not contain the scripts).
Woody does not contain ekg package.
ekg2 (in experimental) does not contain the vulnerable scripts.
please issue a DSA
Marcin
--
Marcin Owsiany <[EMAIL PROTECTED]> http://marcin.owsiany.pl/
GnuPG: 1024D/60F41216 FE67 DA2D 0ACA FC5E 3F75 D6F6 3A0D 8AA0 60F4 1216
interdiff debian/ekg_1.5+20050411-4.diff.0 debian/ekg_1.5+20050411-4.diff
diff -u ekg-1.5+20050411/debian/changelog ekg-1.5+20050411/debian/changelog
--- ekg-1.5+20050411/debian/changelog 2005-05-24 19:14:30.000000000 +0200
+++ ekg-1.5+20050411/debian/changelog 2005-07-13 21:30:21.829781920 +0300
@@ -1,3 +1,12 @@
+ekg (1:1.5+20050411-4) stable-security; urgency=medium
+
+ * Security upload
+ * Fixes symlink creation and potential shell injection vulnerabilities in
+ user-contributed example scripts. (CAN-2005-1916) (CAN-2005-XXXX -
+ optionally if we decide to get new one). Closes: #318059
+
+ -- Marcin Owsiany <[EMAIL PROTECTED]> Wed, 13 Jul 2005 21:25:04 +0300
+
ekg (1:1.5+20050411-3) unstable; urgency=high
* Applied patches selected from upstream CVS, to fix the following important
only in patch2:
unchanged:
--- ekg-1.5+20050411.orig/contrib/ekgh 2002-10-30 01:00:00.000000000 +0200
+++ ekg-1.5+20050411/contrib/ekgh 2005-07-13 21:33:26.810660552 +0300
@@ -44,15 +44,8 @@
#Żeby się cudzysłowy, przecinki, oraz \r \n dobrze wyświetlały...
-tail -n $ILELINII $HISTFILE | sed -e 's/\\r/\\\\r/g; s/\\n/\\\\n/g; s/,"/,/;
s/"$//; s/*/"*"/g' > /usr/tmp/gg_history
-
- # czemu * wyświetla zaw. katalogu?
- # *uj ją tam wie :>
-
-
-#No to sru
-
-cat /usr/tmp/gg_history | while read linia; do
+tail -n $ILELINII $HISTFILE | sed -e 's/\\r/\\\\r/g; s/\\n/\\\\n/g; s/,"/,/;
s/"$//; s/*/"*"/g' | \
+while read linia; do
DATA_S=$(echo $linia | cut -d "," -f4 )
DATA=$(date -d "1970-01-01 `echo $DATA_S` sec UTC" +"%Y-%m-%d %T")
only in patch2:
unchanged:
--- ekg-1.5+20050411.orig/contrib/ekgnv.sh 2002-03-30 01:00:00.000000000
+0200
+++ ekg-1.5+20050411/contrib/ekgnv.sh 2005-07-13 21:33:26.847654928 +0300
@@ -8,7 +8,7 @@
#
# Zmienne dla ~/.ekgnv :
# WGET= ścieżka do wget'a
-# EKGTMP= gdzie ma wrzucać pliki tymaczasowe
+# EKGTMP= gdzie zostanie utworzony podkatalog na pliki tymaczasowe
# EKGWWW= adres strony ekg.
# EKGCONF= co ma podawać do configure gdy automatycznie budujesz ekg
# LASTEKG= ostatnia zainstalowana werja ekg
@@ -40,6 +40,15 @@
# Wczytaj ustawienia.
. ~/.ekgnv
+# wymyslamy bezpieczny podkatalog
+EKGTMPS="$EKGTMP/ekgnv-$$"
+mkdir "$EKGTMPS"
+if [ "$?" != "0" ]; then
+ echo "Proba utworzenia katalogu tymczasowego \"$EKGTMPS\" nie powiodla
sie." >&2
+ echo "Posprzataj \"$EKGTMP\" i sprobuj ponownie." >&2
+ exit 1
+fi
+
# Czy w systemie jest wget?
function check_wget {
if [ ! -x "$WGET" ]; then \
@@ -52,13 +61,13 @@
function get_list {
check_wget
echo -n "Ściągam listę wersji EKG. Poczekaj chwilę. "
- wget -q -P $EKGTMP $EKGWWW/download.php
+ wget -q -P $EKGTMPS $EKGWWW/download.php
# to mozna zamienic na odczytywanie pliku ktory bylby automatycznie po
# twojej stronie generowany, a w ktorym bylby tylko numer najnowszej
# werjsji
- LASTES="`grep ekg-20 $EKGTMP/download.php | cut -d\ -f6 | \
+ LASTES="`grep ekg-20 $EKGTMPS/download.php | cut -d\ -f6 | \
cut -d\\" -f2 | tail -1 | sed -e s/.tar.gz//`"
- rm -f $EKGTMP/download.php*
+ rm -f $EKGTMPS/download.php*
echo "Gotowe!"
}
@@ -82,13 +91,13 @@
check_new
if [ ! -z "$NEW" ]; then \
echo -n "Ściągam ją, poczekaj chwilę. "
- wget -q -P $EKGTMP $EKGWWW/$LASTES.tar.gz
+ wget -q -P $EKGTMPS $EKGWWW/$LASTES.tar.gz
cat ~/.ekgnv | sed -e s/$LASTEKG/$LASTES/ > ~/.ekgtmp
# lub jak ktos nie ma seda to grep -v "LASTEKG" ~/.ekgnv > ~/.ekgtmp
# echo "export LASTEKG=$LASTES" >> ~/.ekgtmp
mv -f ~/.ekgtmp ~/.ekgnv
echo "Gotowe.
-Plik znajduje się w $EKGTMP/$LASTES.tar.gz"
+Plik znajduje się w $EKGTMPS/$LASTES.tar.gz"
else
echo
fi
@@ -99,11 +108,11 @@
get_new
if [ ! -z "$NEW" ]; then \
echo -n "Buduje nowe EKG. Poczekaj chwilę. "
- ( cd $EKGTMP ;
+ ( cd $EKGTMPS ;
tar -zxf $LASTES.tar.gz ; cd $LASTES ;
./configure $EKGCONF > /dev/null ; # tylko błędy będą na konsoli.
make ; make install > /dev/null ;
- rm -rf ../$LASTES* ; )
+ cd .. ; rm -rf $LASTES $LATES.tar.gz ; )
echo "Skończyłem. Masz już najnowszą wersję."
fi
}
only in patch2:
unchanged:
--- ekg-1.5+20050411.orig/contrib/getekg.sh 2002-05-29 01:00:00.000000000
+0300
+++ ekg-1.5+20050411/contrib/getekg.sh 2005-07-13 21:33:26.848654776 +0300
@@ -7,8 +7,13 @@
echo "Podaj zmienne (\"--prefix=/usr\" itp.) dla configure'a!";
exit 1;
fi
-echo "Wchodzę do katalogu tymczasowego."
-cd /tmp
+DIR="${TMPDIR:-${TMP:-/tmp}}/getekg-$$"
+if ! mkdir "$DIR"; then
+ echo "Nie udalo sie utworzyc katalogu tymczasowego \"$DIR\"." >&2
+ exit 1
+fi
+echo "Wchodzę do katalogu tymczasowego \"$DIR\"."
+cd "$DIR"
echo -n "Ściągam najnowszą wersję."
if [ ! -x "`which wget`" ]; then \
if [ ! -x "`which curl`" ]; then \
only in patch2:
unchanged:
--- ekg-1.5+20050411.orig/contrib/scripts/ekgbot-pre1.py 2003-06-29
21:19:00.000000000 +0300
+++ ekg-1.5+20050411/contrib/scripts/ekgbot-pre1.py 2005-07-13
21:33:26.888648696 +0300
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+# -*- coding: ISO-8859-2 -*-
# ekg-bot 0.1-pre1
# Copyright (C) 2003 Andrzej Lindnał
#
@@ -25,6 +26,8 @@
from urllib import * # Obsługa www
from time import * # Operacje czasowe
from random import Random # Random
+from os import * # do implementacji popen
+#import sys # debugowanie
implementacji popen
# Konfiguracja
owner = twojnumer # Numer gg ownera
@@ -80,7 +83,7 @@
if text[0] == "@":
if uin != owner:
- ekg.command("msg %d Czy Ty, aby na pewno jesteś
właścicielem tego bota?;)" % uin)
+ ekg.command("msg %d Czy Ty aby na pewno jesteś
właścicielem tego bota?;)" % uin)
return
tablica = ownerz
elif text[0] == "!": tablica = userz
@@ -99,14 +102,17 @@
try: funkcja, ilosc = tablica[kom]
except: return
+ # jesli komenda wymaga argumentow
if ilosc > 0:
splitarg = arg.split()
args = splitarg[:ilosc]
if len(splitarg) > ilosc:
args.append(string.join(splitarg[ilosc:]))
+ # jesli komenda nie wymaga argumentow
elif ilosc == 0:
if len(arg) > 0: args = [arg]
else: args = []
+ # bledny wpis w liscie komend
else: return
try: funkcja(uin, *args)
@@ -307,17 +313,15 @@
try:
ekg.command("add %d %s" % (int(duin), nazwa))
ekg.command("msg %d Dodałem %s (%s) do listy kontaktów." %
(uin, duin, nazwa))
- except: ekg.command("msg %d Pierwszy parametro to UIN, a drugi NAZWA."
% uin)
+ except: ekg.command("msg %d Pierwszy parametr to UIN, a drugi NAZWA." %
uin)
def freestats(uin):
free = os.popen("%s -m" % path_free).read()
ekg.command("msg %d %s" % (uin, free))
- os.popen("%s -m" % path_free).close()
def hddstats(uin):
df = os.popen("%s -h" % path_df).read()
ekg.command("msg %d %s" % (uin, df))
- os.popen("%s -h" % path_df).close()
def refstatus(uin):
status_ref = strftime("%a, %d %b %Y %H:%M:%S %Z")
@@ -332,9 +336,8 @@
ekg.command("msg %d %s" % (uin, checkurl.info().getheader('Server')))
def ciekhost(uin, host):
- qmer = os.popen("%s %s" % (path_host, re.escape(host))).read()
+ qmer = safepopen([path_host, host])
ekg.command("msg %d %s" % (uin, qmer))
- os.popen("%s %s" % (path_host, re.escape(host))).close()
def fetchmail(uin):
os.popen("%s" % path_fetchmail)
@@ -351,6 +354,7 @@
ekg.command("block %d" % ktos)
ekg.command("msg %d %d został zablokowany" % (uin, ktos))
except: ekg.command("msg %d Musisz podać parametr jako UIN do
zablokowania" % uin)
+
def unblock(uin, numer):
try:
numer = int(numer)
@@ -393,16 +397,13 @@
def uname(uin):
ekg.command("msg %d %s" % (uin, os.popen("%s -mnrs" %
path_uname).read()))
- os.popen("%s -mnrs" % path_uname).close()
def krot(uin, ile, tekst):
ile = int(ile)
if ile < 2 or ile > 23: ekg.command("msg %d Jako pierwszy parametr
należy podać liczbę z zakresu 2-23." % uin)
else:
try:
- cmdline = "%s -ear%d %s" % (path_erecoder, ile,
re.escape(tekst))
- ekg.command("msg %d %s" % (uin,
os.popen(cmdline).read()))
- os.popen(cmdline).close()
+ ekg.command("msg %d %s" % (uin,
safepopen([path_erecoder, '-ear'+ile, '--', tekst])))
except: ekg.command("msg %d Jako pierwszy parametr należy podać
liczbę z zakresu 2-23." % uin)
def drot(uin, ile, tekst):
@@ -410,9 +411,7 @@
if ile < 2 or ile > 23: ekg.command("msg %d Jako pierwszy parametr
należy podać liczbę z zakresu 2 - 23." % uin)
else:
try:
- cmdline = "%s -dar%d %s" % (path_erecoder, int(ile),
re.escape(tekst))
- ekg.command("msg %d %s" % (uin,
os.popen(cmdline).read()))
- os.popen(cmdline).close()
+ ekg.command("msg %d %s" % (uin,
safepopen([path_erecoder, '-dar'+ile, '--', tekst])))
except: ekg.command("msg %d Jako pierwszy parametr należy podać
liczbę z zakresu 2-23" % uin)
def kbase(uin, tekst):
@@ -496,6 +495,7 @@
ekg.command("msg %d Wylosowane przez komputer liczby do losowań
Zakładów Specjalnych to: %s" % (uin, lotto(42,5)))
else:
ekg.command("msg %d Nieznany parametr! Parametry:\r\nmulti,
duzy, express, zaklady" % uin)
+
def sin(uin, liczba):
try: ekg.command("msg %d %s" % (uin, trygonometria('sin', liczba)))
except: ekg.command("msg %d Błędne wywołanie." % uin)
@@ -523,14 +523,10 @@
?polecenie. Na przykład: ?status.\r\nAutorem tego bota jest
Andrzej Lindnał""" % uin)
def kmorse(uin, tekst):
- cmdline = "%s -eam -- %s" % (path_erecoder, re.escape(tekst))
- ekg.command("msg %d %s" % (uin, os.popen(cmdline).read()))
- os.popen(cmdline).close()
+ ekg.command("msg %d %s" % (uin, safepopen([path_erecoder, '-eam', '--',
tekst])))
def dmorse(uin, tekst):
- cmdline = "%s -dam -- %s" % (path_erecoder, re.escape(tekst))
- ekg.command("msg %d %s" % (uin, os.popen(cmdline).read()))
- os.popen(cmdline).close()
+ ekg.command("msg %d %s" % (uin, safepopen([path_erecoder, '-dam', '--',
tekst])))
def bmi(uin, masa, wzrost):
try:
@@ -561,3 +557,27 @@
def killme(uin):
ekg.command("msg %d Wyłączam EKG. Aby mnie ponownie włączyć, będziesz
musiał zalogować się na shella niestety;))" % uin)
ekg.command("quit")
+
+
+def safepopen(cmd):
+ rfd, wfd = pipe()
+ ret = fork()
+ # child
+ if ret == 0:
+ close(rfd)
+ dup2(wfd, 1)
+ execv(cmd[0], cmd)
+ exit(1)
+ # parent
+ else:
+ close(wfd)
+# sys.stderr.write('reading..')
+ readstring = read(rfd, 4094)
+# sys.stderr.write('got it!')
+ while read(rfd, 4096) != '':
+ pass
+# sys.stderr.write('EOF')
+ waitpid(ret, 0)
+# sys.stderr.write('reaped')
+ return readstring
+
only in patch2:
unchanged:
--- ekg-1.5+20050411.orig/contrib/scripts/linki.py 2003-06-29
23:29:58.000000000 +0300
+++ ekg-1.5+20050411/contrib/scripts/linki.py 2005-07-13 21:33:26.926642920
+0300
@@ -1,14 +1,21 @@
+# -*- coding: ISO-8859-2 -*-
# Skrypt ten uruchamia się z poziomu ekg (polecenie python) a zadanie jego to
# wyłapywanie adresów URL w otzymanych wiadomościach. Mozna by w tym miejscu
poopowiadać o działaniu skryptu
# ale myśle ze skypt jest dosć rozmowny pozatym by poczytać helpa (i nie
tylko) wystarczy nacisnąć F8
# wszelkie pretensje można kierować na adres: rmrmg(at)wp(dot)pl
+#
+# poprawki bezpieczeństwa: wojtekka (2005-07-11)
+
import re
import ekg
import string
import os
+browser="firefox"
link=re.compile(".*http.*")
linka=re.compile("http.*")
+linkfile=os.path.expanduser("~/.gg/rmrmg_ekg_url")
+
def init ():
ekg.printf("generic", "linkownik")
return 1
@@ -17,6 +24,17 @@
ekg.printf("generic", "linkownik poszedł")
return 1
+def launch(url, tab):
+ url = string.replace(string.replace(url, ",", "%2c"), "'", "%27");
+
+ if tab:
+ command = "%s -remote 'openURL(%s, new-tab)'" % (browser, url)
+ else:
+ command = "%s '%s'" % (browser, url)
+
+ #ekg.printf("generic", "[%s]" % (command))
+ os.system(command)
+
def handle_msg(uin, name, msgclass, text, time, secure):
#ekg.printf("generic", "echo działa")
if link.match(text):
@@ -26,7 +44,7 @@
ekg.printf("generic", "znaleziono link: %s" %(x))
ekg.printf("generic", "by otworzyć w: nowym oknie wcisnij F7,
nowej zakładce F5, by nie otwierac wciśnijF6.")
ekg.printf("generic", "F8 pokazuje liste przechwyconych linków;
F5-F7 działa na pierwszym linku z listy")
- os.system("echo \"%s\" >> /tmp/rmrmg_ekg_url" %(x))
+ open(linkfile, 'a').write(x + '\n');
#ekg.printf("generic","echo tada")
return 1
else:
@@ -42,13 +60,13 @@
dlug=len(nurl)
if dlug == 1:
ekg.printf("generic", "otwieram %s w nowej zakładce" %(nurl[0]))
- os.system("MozillaFirebird -remote 'openURL(%s, new-tab)'"
%(nurl[0]))
- os.system('rm /tmp/rmrmg_ekg_url')
+ launch(nurl[0], True)
+ os.unlink(linkfile)
else:
ekg.printf("generic", "linków mam %d" %(dlug))
wielejest(nurl)
ekg.printf("generic", "otwieram %s w nowej zakładce" %(nurl[0]))
- os.system("MozillaFirebird -remote 'openURL(%s, new-tab)'"
%(nurl[0]))
+ launch(nurl[0], True)
elif key == 270:
ekg.printf("generic", "wcisnięto F6")
nurl=czyjest()
@@ -58,7 +76,7 @@
dlug=len(nurl)
if dlug == 1:
ekg.printf("generic", "kasuje adres %s" %(nurl[0]))
- os.system('rm /tmp/rmrmg_ekg_url')
+ os.unlink(linkfile)
else:
ekg.printf("generic", "jest wiele linków")
wielejest(nurl)
@@ -72,8 +90,8 @@
dlug=len(nurl)
if dlug == 1:
ekg.printf("generic", "otwieram %s w nowym oknie" %(nurl[0]))
- os.system("MozillaFirebird %s" %(nurl[0]))
- os.system('rm /tmp/rmrmg_ekg_url')
+ launch(nurl[0], False)
+ os.unlink(linkfile)
else:
ekg.printf("generic", "linków mam %d" %(dlug))
wielejest(nurl)
@@ -93,8 +111,8 @@
###########################################################
def czyjest ():
- if os.path.exists('/tmp/rmrmg_ekg_url'):
- wejsc= open ('/tmp/rmrmg_ekg_url')
+ if os.path.exists(linkfile):
+ wejsc= open (linkfile)
file = wejsc.readlines()
dlug=len(file)
wejsc.close()
@@ -104,9 +122,9 @@
return 0
def wielejest (buff):
- file=open('/tmp/rmrmg_ekg_url' , 'w')
+ file=open(linkfile , 'w')
#buff= file.readlines()
#file.truncate()
#file.writelines
file.writelines('\n'.join (buff[1:]))
- file.close()
\ Brak znaku nowej linii na końcu pliku
+ file.close()
#-diff -u debian/ekg_1.5+20050411-4.diff.0 debian/ekg_1.5+20050411-4.diff
_______________________________________________
Secure-testing-team mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/secure-testing-team