CTF/InsomniHack-2018/Spoke

From Fixme.ch
Jump to: navigation, search

Challenge

An administrator changed the VPN configuration to IKEv1 main mode.

Try to access to intranet website.

What's inside the archive?

Let's have a look what's inside this archive, we have a PCAP traffic capture and some IPSec debug informations (include keys!) coming from a Fortinet device.

user@kali:~/ins18/Spoke$ zipinfo 7a071362b981aa2a4d97a7307054ca43.zip
Archive:  7a071362b981aa2a4d97a7307054ca43.zip
Zip file size: 10794 bytes, number of entries: 3
drwx---     6.3 fat        0 bx stor 18-Mar-23 16:50 upload/
-rw-a--     6.3 fat     1758 bx defN 18-Mar-23 16:58 upload/DebugFortigateHub.txt
-rw-a--     6.3 fat    12190 bx defN 18-Mar-23 16:39 upload/Sniffer.txt.pcap
3 files, 13948 bytes uncompressed, 10320 bytes compressed:  26.0%
user@kali:~/ins18/Spoke$ cat upload/DebugFortigateHub.txt 
pwn-spoke (ext) # diagnose vpn ike gateway list

vd: ext/2
name: dia_0
version: 1
interface: port2 4
addr: 10.13.37.70:500 -> 10.13.38.122:500
created: 61s ago
peer-auth: yes
assigned IP address: 10.249.2.4/0.0.0.0
auto-discovery: 0
IKE SA: created 1/1  established 1/1  time 10/10/10 ms
IPsec SA: created 1/1  established 1/1  time 20/20/20 ms

  id/spi: 13 956a636e90da6ce5/6abab248b8ffd14e
  direction: responder
  status: established 61-61s ago = 10ms
  key: 4e67a953bb27a382-acadbb7ebfdb6a02-79d21346cc5d8f39

pwn-spoke (ext) # diagnose vpn tunnel list
list all ipsec tunnel in vd 2
------------------------------------------------------
name=dia ver=1 serial=1 10.13.37.70:0->0.0.0.0:0
bound_if=4 lgwy=static/1 tun=intf/0 mode=dialup/2 encap=none/0
proxyid_num=0 child_num=1 refcnt=12 ilast=7659 olast=7659 auto-discovery=0
stat: rxp=0 txp=0 rxb=0 txb=0
dpd: mode=on-demand on=0 idle=20000ms retry=3 count=0 seqno=0
natt: mode=none draft=0 interval=0 remote_port=0
------------------------------------------------------
name=dia_0 ver=1 serial=f 10.13.37.70:0->10.13.38.122:0
proxyid=dia proto=0 sa=1 ref=2 serial=1 add-route
  SA: ref=3 options=2a6 type=00 soft=0 mtu=1438 expire=3525/0B replaywin=2048 seqno=8 esn=0 replaywin_lastseq=00000034
  life: type=01 bytes=0/0 timeout=3590/3600
  dec: spi=6e0310cf esp=aes key=32 8385255e143ca436f939aaa68bc0f5a240c4870a7ba499584ac280a6ac015617
       ah=sha256 key=32 e9f5bec30e3e8cb39e9f847dd84ed16843ada8b4d63c6e557234129d2b3c655e
  enc: spi=c71e7371 esp=aes key=32 3314e5045dbbc392821fb545dbd002bb5b57b77994639b7d7d987ec9da92fd07
       ah=sha256 key=32 36165b2f33ceaf2917bc2f9b0e073844133d320bf0c3067f7ca44308cca92b53
  dec:pkts/bytes=52/4223, enc:pkts/bytes=7/948
user@kali:~/ins18/Spoke$ 

Decrypt the traffic

Analysing the traffic capture, we can find IPSec encrypted traffic between two endpoints 10.13.38.122 and 10.13.37.70. Fortunately, the Fortinet debug output gives us the session keys that can be used to decrypt ESP traffic directly in wireshark.

Configuring ESP SAs
Configuring IKEv1 Decryption Table

This packet shows us the actual target of this challenge:

24  4.503228    10.13.38.122    10.249.251.10   DNS 170 Standard query 0x6561 A intranet.gloup.adds OPT

Crack the PSK

Next step is to recover the PSK, to do that we had to build a file containing necessary parameters for the psk-crack utility coming from the ike-scan project. The format of the file can be found by reading through the source code.

user@kali:~/ins18/Spoke$ cat params.py 
#!/usr/bin/env python3

g_xr = "528cd7b2648016f481c8b54eeab60dbbeae00a872ab1545ae76ea22e536f62b4b2797dbbf57b1c760123258e1f30b4a8ffc8612c1683de67b566147106c17b7105130343bf5ab0bdc2a2cf104343d7d2630ce2cd9d3593e5f76bcfa28e14e86d3b31d06ac110b638947ad07db26c760775a08ff828904a147616be4e8c1f007c81e2c442e4d42a463cdfe5e37e2556e48d4f6a8c5fc967b57d1218285f06b281d3a3d3d3245ba61944a6320fa2eba32f0e2040a6bec626a5c9d1775594fc2061"

g_xi = "7ee3d1fc510d8e7c87e293b10e57d8881e2e7055430299e98c040bbd1b878275ba02e6f33b01174e7173cadefecb45132f6ee0bc88fc882c774f36ff835e76238a4577d5bc3b09367d879ec62c1da17813c02a1c09baaf1681838dbdc693bd323b42a240cdc38672306d5aa83f923bc4c9f1f14830e642e6b24931c659c8d218990f51eed03917b495a7be855a66178c6a38bc672ce5f7b95701aee61e6acf8642102de424a04ec81b9496448461587fcfaa2dbd5fdc099e509759f636a24cbe"

cky_r = "6abab248b8ffd14e"

cky_i = "956a636e90da6ce5"

sai_b = "00000001000000010000006400010003030000200101000080010005800200018004000580030001800b0001800c7080030000240201000080010007800e0080800200048004001380030001800b0001800c708000000018030100008004001380030001800b0001800c7080"

idir_b = "02000000487562"

ni_b = "22a8341e9b107ff273c4aa74c7659a00e374bae2df9e53c656669fa5282b555e"

nr_b = "c6922c8a4bc3a16574299f792966017b"

hash_r = "f3a0cb7a7a681a9b06f72d9575620b66"

print(':'.join((g_xr, g_xi, cky_r, cky_i, sai_b, idir_b, ni_b, nr_b, hash_r)))
user@kali:~/ins18/Spoke$ ./params.py | psk-crack /dev/stdin 
Starting psk-crack [ike-scan 1.9.4] (http://www.nta-monitor.com/tools/ike-scan/)
Running in dictionary cracking mode
key "island" matches MD5 hash f3a0cb7a7a681a9b06f72d9575620b66
Ending psk-crack: 175930 iterations in 0.321 seconds (548030.98 iterations/sec)
user@kali:~/ins18/Spoke$ 

Setup an IPSec tunnel

Now that we have all necessary IPSec parameters as well as the PSK, it's time to setup an IPSec tunnel to hopefully reach this intranet server. We're using Strongswan with the following configuration which took so many iterations before working as expected.

ipsec.conf:

# ipsec.conf - strongSwan IPsec configuration file

config setup
    charondebug="ike 2, cfg 0, esp 2, chd 2, cfg 2"

conn insomnihack
        type=tunnel
        authby=secret
        left=%defaultroute
        leftsubnet=0.0.0.0/0
        leftid=Ins0mn1
        right=10.13.37.70
        rightsubnet=10.249.0.0/16
        rightid=Hub
        keyexchange=ikev1
        ike=3des-md5-modp1536
        esp=aes256-sha256-modp1536
        auto=start

ipsec.secrets:

# This file holds shared secrets or RSA private keys for authentication.

: PSK "island"

The tunnel is now up and running but we still cannot access the target server (10.249.251.10), outgoing traffic seems to be correctly sent through the IPSec tunnel but no replies are coming back.

Setup BGP routing

This is where we can start to understand why this BGP session from the PCAP might actually be useful.

We're going to setup our good old friend Quagga (`apt install quagga`) as a BGP speaker to announce our own IP to the network equipment at the other end of the tunnel.

All of the parameters can be extracted from the PCAP:

  • ASN: 65515
  • IBGP session, the same ASN is used on both ends
  • Remote peer: 10.249.252.1
  • Two prefixes are being announced:
    • 10.249.2.4/32
    • 10.13.38.122/32

The first IP (10.249.2.4) was received during the IPSec configuration phase.

The second one (10.13.38.122) is used as a source IP for talking to the target server (10.249.251.10).

As we are lazy and didn't bother with the IPSec Config mode (ISAKMP_CFG_REQUEST in the PCAP), we had only a single IP address, so we simply tried to announce it (192.168.7.102) directly in the BGP session and fortunately it worked!

bgpd.conf:

!
! Zebra configuration saved from vty
!   2018/03/24 01:04:26
!
!
router bgp 65515
 bgp router-id 192.168.7.102
 network 192.168.7.102/32
 neighbor 10.249.252.1 remote-as 65515
!
 address-family ipv6
 exit-address-family
 exit
!
line vty
!

Get the flag

So now, connectivity toward the target network is working (10.249.251.0/24) and we can finally resolve the IP address of intranet.gloup.adds and connect to it to get the flag!

user@kali:~$ dig +short intranet.gloup.adds @10.249.251.10
10.249.251.10
user@kali:~$ curl -H "Host: intranet.gloup.adds" http://10.249.249.10/
INS{G1v3_M3_Y0ur_PSK}
user@kali:~$ 

Wrap up

We actually spent quite some time on this challenge (6-7 hours) but it was worth it! It had a good mix of finding a needle in a haystack, applied cryptography and network magic but perhaps too many ways to get lost during its resolution :)