Gilks / hostscan-bypass

Generate OpenConnect CSD files to bypass Cisco AnyConnect hostscan requirements
247 stars 46 forks source link

Login denied (multiple issues) #11

Closed somewhereinthepacific closed 4 years ago

somewhereinthepacific commented 4 years ago

Hello.

I cannot make "hostscan-bypass.sh" work for some reason. Let me list here what I have found so far in case you can point me in the right direction:

This is all the data that "hostscan-bypass.go" captures in my case:

POST /
    HTTP/1.1
    Cache-Control: no-cache
    Connection: close
    Pragma: no-cache
    User-Agent: AnyConnect Windows 4.8.0305
    X-Transcend-Version: 1
    X-AnyConnect-STRAP-Pubkey: KLe09...Cq==
    X-Aggregate-Auth: 1
    Content-Length: 838
    Host: ...

    DATA (computer name, mac address, auth method, ...)

GET /CACHE/sdesktop/install/binaries/update.txt
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Close
    Pragma: no-cache
    User-Agent: AnyConnect Windows 4.8.0305
    X-Transcend-Version: 1
    X-AnyConnect-STRAP-Pubkey: KLe09...Cq==
    X-Aggregate-Auth: 1
    Host: ...

GET /CACHE/sdesktop/paths.txt
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Close
    Pragma: no-cache
    User-Agent: AnyConnect Windows 4.8.0305
    X-Transcend-Version: 1
    X-AnyConnect-STRAP-Pubkey: KLe09...Cq==
    X-Aggregate-Auth: 1
    Host: ...

HEAD /
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /+CSCOE+/sdesktop/token.xml?ticket=4AB...77&stub=0
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /CACHE/sdektop/hostscan/windows_i386/manifest
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /+CSCOT+/translation-table?type=mo&textdomain=csd&lang=en-us
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /+CSCOT+/translation-table?type=mo&textdomain=csd&lang=en-us
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

HEAD / 
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /+CSCOE+/sdesktop/token.xml?ticket=4AB...77&stub=0
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

HEAD /CACHE/sdesktop/data.xml 
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /CACHE/sdesktop/data.xml 
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /+CSCOL+/opswatlicense.html 
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Host: ...

GET /CACHE/sdesktop/hostscan/windows_i386/manifest
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Cookie: sdesktop=54...31
    Host: ...

POST /
    HTTP/1.1
    Cache-Control: no-cache
    Connection: close
    Pragma: no-cache
    User-Agent: AnyConnect Windows 4.8...
    X-Transcend-Version: 1
    X-AnyConnect-STRAP-Pubkey: KLe09...Cq==
    X-Aggregate-Auth: 1
    Content-Length: 916
    Host: ...

    DATA (computer name, mac address, auth method, ...)

POST /+CSCOE+/sdesktop/scan.xml ...
    HTTP/1.1
    Cache-Control: no-cache
    Connection: Keep-Alive
    Pragma: no-cache
    Content-Type: text/xml
    Cookie: sdesktop=54...31
    Content-Length=14205
    Host: ...

    DATA (all "juicy" information):
        endpoint.os.version="Windows 10";
        endpoint.os.architecture="x64";
        ...
        endpoint.pfw[...].description="Windows Firewall";
        endpoint.pfw[...].enabled="ok";
        ...

Anyway... I see that "hostscan-bypass.go" parses all these packets and does two things:

  1. If packet data contains the string "endpoint", saves this for later, to be sent inside the "hostscan-bypass.sh" POST to the server.
  2. If packet data contains the string "User-Agent" and "X-AnyConnect-Platform", it saves the values of these two headers to later use them when creating the forged "hostscan-bypass.sh" POST.

I already see an issue with (2), as none of the packets in my case contain those two headers at the same time. I had to manually edit the generated "hostscan-bypass.sh" script to change "\<PLAT>" to "win" and "\<USERAGENT>" to "AnyConnect Windows 4.8.0305". But it wouldn't work either.

Another option was to also include the "X-AnyConnect-STRAP-Pubkey" header. But again, no luck.

In particular, with this "hostscan-bypass.sh" script, when I exeuted this:

sudo openconnect -v -v -v --useragent="AnyConnect Windows 4.8.0305" --dump-http-traffic --csd-wrapper=/home/alexander/bin/hostscan/hostscan-bypass.sh vpn.mycompany.com --os=win

...this is what I get:

> POST /
...
Got HTTP response: HTTP/1.1 200 Ok
...
<message> Please enter username and password </message>
<host-scan-ticket>67...</host-scan-ticket>
<host-scan-token>4A...</host-scan-token>
...
> GET .../sdesktop/wait.html
...
Got HTTP response: HTTP/1.1 302 Moved Temporarily
...

> POST /
...
Got HTTP response: HTTP/1.1 200 Ok
...
<message> Please enter username and password </message>
<host-scan-ticket>7B...</host-scan-ticket>
<host-scan-token>55...</host-scan-token>
...

> POST /
...
Got HTTP response: HTTP/1.1 200 Ok
...
message> Please enter username and password </message>
<host-scan-ticket>A9...</host-scan-ticket>
<host-scan-token>6C...</host-scan-token>
...

...and the I'm asked for my login/password.

Some extra issues I see here all have to do with the number of "host-scan-ticket" fields I receive (three in total) and the number of times "hostscan-bypass.sh" is called (which seems to be only one, with the first token).

Is it normal to receive three tokens? (Maybe it has to do with the 302 redirect?). Should "hostscan-bypass.sh" be executed three times (one for each token)? I have manually tried to execute it those two additional times (with tokens #2 and #3) before entering the login/password, but again no luck.

Any idea of what I could do next?

Thanks for your time.

somewhereinthepacific commented 4 years ago

Update: I figured out what the issue was.

Changing line 77 of the script so that it uses --data-binary instead of --data-ascii fixed the problem for me.

(Well... that and manually updating the HTTP headers so that they include correct values)

When using "--data-ascii" curl removes newlines and my VPN server does not seem to like that.

Anyway, do you think this change could be merged? What is the advantage of using "--data-ascii"?

Also, in regard to the three different sets of "host-scan-ticket"+"host-scan-token", it looks like it is OK as long as the forged host scan reply and the request containing the login/password make reference to the same CSD token, which is what openconnect does.

Gilks commented 4 years ago

Thanks for the detailed report! It sounds like you got into the weeds on this one. Out of curiosity, what error message were you getting when trying to authenticate with openconnect?

I can't really speak to the differences between --data-ascii and --data-binary as that was part of the original code that I found by a user named Fromzy. I'll have to test that change on another network to verify everything still works as intended.

EDIT: I just verified that changing the --data-ascii flag to --data-binary works just fine on AnyConnect 4.5. If you want to put in a PR, I'll happily merge it in so you get credit. It's interesting no one has run into this so far.

somewhereinthepacific commented 4 years ago

Out of curiosity, what error message were you getting when trying to authenticate with openconnect?

It was the same "login failure" response I get when some of the fields on the forged request are missing.

For example, my VPN server expects the CSD script to report that Windows Firewall is active. If I were to change the forged packet to not include that piece of information, it would fail in the same way (ie. "login failure").

For all of this, I would say that not including the newlines confuses the VPN server which just treats the CSD reply as an empty one.