AI prompts
base on Cisco IOS XE implant scanning & detection (CVE-2023-20198, CVE-2023-20273) # Cisco IOS XE implant scanning & network detection
Network detection of `CVE-2023-20198` exploitation and fingerprinting of post-exploitation of Cisco IOS XE devices.
## CVE-2023-20198 Suricata network detection
The [suricata/](suricata/) folder contains Suricata detection rules for exploitation of `CVE-2023-20198`. These rules monitor for a percent-encoded-percent which can be used to bypass authentication on Cisco IOS XE devices not patched for `CVE-2023-20198`.
This directory also contains reference PCAPs based on observed in-the-wild exploitation traffic:
* [fox-it-cisco-cve-2023-20198-auth-bypass-wsma-exec.pcap](suricata/fox-it-cisco-cve-2023-20198-auth-bypass-wsma-exec.pcap?raw=true) -- CVE-2019-20198 exploit with wsma-exec
* [fox-it-cisco-cve-2023-20198-auth-bypass-wsma-config.pcap](suricata/fox-it-cisco-cve-2023-20198-auth-bypass-wsma-config.pcap?raw=true) -- CVE-2019-20198 exploit with wsma-config
## Cisco IOS XE implant scanning
This repository also contains information regarding post-exploitation activities linked to the Cisco IOS XE Software Web Management User Interface mass exploitations. Cisco Talos [^1] published a fingerprint that could check if the implant was active on Cisco IOS XE devices. For reference:
```shell
curl -k -X POST "https://DEVICEIP/webui/logoutconfirm.html?logon_hash=1"
```
If the HTTP response consists of a hexadecimal string, this is a high-confidence indicator that the device is compromised. However, as multiple sources have mentioned [^2] [^3], the number of implants that can be discovered using this method has gone down significantly.
## Upgraded Implant
Investigated network traffic to a compromised device has shown that the threat actor has upgraded the implant to do an extra header check.
Thus, for a lot of devices, the implant is still active, but now only responds if the correct `Authorization` HTTP header is set.
## Alternate method for Cisco IOS XE implant scanning
We took another look at the [initial blogpost by Cisco Talos](https://blog.talosintelligence.com/active-exploitation-of-cisco-ios-xe-software/) and noticed an extra location check in the implant code:

Based on the above screenshot of the implant code shared by Cisco Talos we found another method that can be used to fingerprint the presence of the implant.
```shell
curl -k "https://DEVICEIP/%25"
```
Using the `%25` (percent encoded percent), we meet the conditions specified in the extra location check. This will cause the server to respond with a different HTTP response than it normally would when the implant is not running.
There are currently three known versions of the implant. As of 1 November 2023, the implant is named `BadCandy` by Cisco Talos [^1].
### BadCandy Implant v1 / v2 response
A telltale of implant operation is a `<head><title>404 Not Found</title></head>` in the body. An example HTTP body is as such:
```html
$ curl -k 'https://DEVICEIP/%25'
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
```
### BadCandy Implant v3 response
The third variant returns the login page rather than the 404. As one would still normally expect a javascript redirect rather than this login page, we can still determine the presence of the implant by checking whether or not a login page is returned:
```html
curl -k 'https://DEVICEIP/%25'
<!DOCTYPE html>
<html>
<!--
Copyright (c) 2015-2019 by Cisco Systems, Inc.
All rights reserved.
-->
<head lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title id="loginTitle"></title>
```
We found different login responses in our scanning results, and ended up with the `name="Username"` string as an identifier to determine whether or not a login page is being returned.
### Other responses
If the implant is not present, you will get a different response. For example:
```html
$ curl -k 'https://DEVICEIP/%25'
<script>window.onload=function(){ url ='/webui';window.location.href=url;}</script>
```
## Script to check for compromise
We created a small script that checks for compromise using the above fingerprinting method. Script can be found here:
* [iocisco.py](iocisco.py)
Example usage:
```shell
$ pip3 install requests
$ python3 iocisco.py 192.168.1.1
[!] Checking http://192.168.1.1/%25
WARNING: Possible implant found for 192.168.1.1 (impant v3)! Please perform a forensic investigation!
[!] Checking https://192.168.1.1/%25
WARNING: Possible implant found for 192.168.1.1 (implant v3)! Please perform a forensic investigation!
```
It is also possible to scan a list of hosts, seperated by newlines.
```shell
$ python3 iocisco.py --file cisco-ips.txt
```
## References
[^1]: https://blog.talosintelligence.com/active-exploitation-of-cisco-ios-xe-software/
[^2]: https://www.bleepingcomputer.com/news/security/number-of-hacked-cisco-ios-xe-devices-plummets-from-50k-to-hundreds/
[^3]: https://twitter.com/onyphe/status/1715633541264900217
", Assign "at most 3 tags" to the expected json: {"id":"4114","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"