Posts | Tags | Archive

Password recovery from an Alcatel-Lucent Cellpipe 7130

Background

In my current rental situation, the landlord provides internet included with the rental. Since it's fast enough and has enough bandwidth this isn't an issue at all. The only problem is that the modem provided by the telco is an ancient Alcatel-Lucent Cellpipe 7130 5VzA2001 modem/router combo. It's running firmware version 1.0.4.4R8-wh, released on 2012-05-08 16:30 (there are no updates, I checked).

Since the Cellpipe only has 4 x 10/100 LAN ports and terrible WiFi performance, I would much prefer to use my own equipment to perform the routing and just use the Cellpipe 7130 as a WAN gateway. Unfortunately, for some reason, there is no way to turn off the routing aspect of the Cellpipe and just use it as a modem (aka bridge mode). There is also no way to turn off DHCP functionality on it.

My current hacky solution to these problems is to let my router get an IP from the modem/router via DHCP, then set that IP as the DMZ host on the Cellpipe. This effectively forwards all TCP and UDP ports to the router, making it seem like it's the boundary device for the network. Luckily, my router always seems to request the same IP no matter what so this continues to work even if both devices are power cycled.

Since this is not an ideal situation, I'd like to replace the Cellpipe with a more performant modem without any of the routing overhead. To do this, I just need to port the configuration details from the Cellpipe (like the username and password for the upstream PPPoE connection) over to a new modem. Unfortunately, there's nothing in the web interface that will allow me to see the password and there's no option to do a configuration backup. I also can't just call up the telco since it's the landlord's account.

This means we're stuck, right?

Digging into the Cellpipe

Doing a quick CVE search for the Cellpipe only turns up CVE-2015-4586 (a CSRF vulnerability) and CVE-2015-4587 (an XSS vulnerability), both of which aren't useful in this case. Oh well.

Seeing as the Cellpipe 7130 manual(PDF) mentions various functionality that my device doesn't seem have, my hypothesis is that there might be a configuration backup/restore function somewhere, just not exposed in the UI. With that in mind, I went trawling through the HTML and JavaScript files the web UI served up. I found:

The color 'red' is commented out and redefined as white. This suggests that they could be hiding error messages by just making them the same color as the background:

1
2
//var red    ='#FF0000';
var red    ='#FFFFFF';

Debugging in production builds with commented out alert statements:

1
2
//alert(isRouter);
//alert(isAPmode);

Various comments indicating lack of source control:

1
2
3
4
5
6
7
8
//Jamie hide 20111109
/*if(menuItem=='HPNA')
{
    printMenuItem('hpna.html', 'HPNA', white, darkBlue);
}else{
    printMenuItem('hpna.html', 'HPNA', black, blue);
}
*/
1
2
//fanny add 2011/02/22
printMenuItem('wifi_statistics.html', 'WLAN Statistics ', black, white);
1
2
3
4
5
<!-- jonathan 2004.04.07    Begin  -->
<form name="logoutForm" method="post">
    <input type="hidden" name="logoutMsg">
</form>
<!-- jonathan 2004.04.07    End  -->

These all seem to allude to shoddy release processes, meaning that it's highly likely that per-model customizations were rushed UI-level hack jobs on top of the current release and not maintained branches where actual functionality was changed.

Since a configuration backup will include the PPPoE username and password, let's do a search for "config". Sure enough:

1
2
3
4
5
6
7
8
printMenuSection('util_main.html', 'Utilities', white);
printMenuItem('lang_set.html', 'Language Setting', black,white);
printMenuItem('util_reboot.html', 'Reboot Gateway', black,white);
//printMenuItem('util_reservice.html', 'Restart Service', black,white);
printMenuItem('util_factory.html', 'Restore Factory Defaults',black, white);
//printMenuItem('util_cfgstore.html', 'Configuration Store', black,white);
//printMenuItem('util_cfgrestore.html', 'Configuration Restore', black,white);
printMenuItem('util_webfirmware.html', 'Web Firmware Upload', black,white);//Jamie add back 20111109

Visiting http://<router_ip>/util_cfgstore.html shows a nice "Store" button that downloads a text file containing 771(!) key/value pairs, including the username and password for the router. Success!

Future plans

There are a ton of other options in the downloaded config file, some of which look like they enable bridge mode. However, flipping those settings on and applying the new config using http://<router_ip>/util_cfgrestore.html didn't seem to change anything. I'm going to keep messing with it while I look into sourcing a better modem to use my newfound credentials with.

Longer-term, the plan is to transition to a dedicated modem that provides WAN access to a low-power computer running pfSense for firewall and routing duties. From there, an unmanaged switch (possibly injecting PoE) can provide access for enough dumb wireless APs to bathe the house in WiFi, as well as wired hookups for the devices that don't move around too much or need the throughput. For now though, I'll settle for replacing the modem.


Forwarding spam with Gmail

With multiple Gmail accounts, it's often easier to forward all emails to a single main account that you actually check. This can be accomplished by setting up a forwarding account in Gmail's settings.

However, something that isn't immediately obvious is that messages that are considered spam are never forwarded. While Gmail's spam detection is extremely good, it's not perfect. There have been times where emails that I actually wanted have ended up in the spam folder and weren't forwarded to my main account.

To fix this, we want to tell Gmail to not flag anything as spam so it will be forwarded along.

Note

This will not cause spam to appear in your inbox. It bypasses the spam filters so the email is forwarded properly, but the account it's forwarded to will also flag the email as spam. The end result is that that the email will end up in the spam folder of your main account (where you can actually look at it) instead of not being forwarded from the original account at all.

We can do this with a filter that matches is:spam and applies the option "Never send it to Spam". Unfortunately, Gmail's interface makes this task much harder than it needs to be.

  1. Open Gmail and do a search for is:spam. Notice that Gmail autocorrects it to in:spam.
  2. Click the dropdown arrow on the right side of the search box to bring down the advanced options and click "Create filter with this search". Hit "OK" on the warning box that pops up. Notice that the filter has been autocorrected again to label:spam.
  3. In the URL you should see something like #create-filter/has=label%3Aspam. Change label to is in the URL and hit enter. It should modify the text in the box without changing anything else.
  4. Check the "Never send it to Spam" checkbox and hit "Create filter". You'll see the text get autocorrected to in:spam again, but if you check in Settings -> Filters and Blocked Addresses you should see the correct is:spam filter.

Bank of Canada currency conversion rates in the terminal

Preface

In this entry I'll use two command line tools (curl and jq) to request currency conversion rates from the Bank of Canada. Now obviously getting the same data through the normal web interface is possible as well. However, doing it this way returns the data in a machine-readable form, allowing it to be customized or used as input into other programs.

The basic flow will be request the data using curl, then pipe it to jq for processing.

Note

This article will request the USD/CAD exchange rate from 2017-01-01 to 2017-01-10. It should be fairly obvious how to switch this for any other currencies or date ranges. See the Appendix for more information and caveats with the dates and the conversion codes.

We'll go from seeing the raw data the server returns to something that we can more easily use. To skip to the final result, click here.

Update

The URLs for the data were originally reverse-engineered from the website. They have since been turned into a supported API. See the API documentation for more details.

Lets go!

Hitting the server without any processing will give the following result:

1
curl -s "https://www.bankofcanada.ca/valet/observations/FXUSDCAD/json?start_date=2017-01-01&end_date=2017-01-10"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
"terms":{
    "url": "http://www.bankofcanada.ca/terms/"
},
"seriesDetail":{
"FXUSDCAD":{"label":"USD/CAD","description":"US dollar to Canadian dollar daily exchange rate"}
},
"observations":[
{"d":"2017-01-02","FXUSDCAD":{"e":-64}},
{"d":"2017-01-03","FXUSDCAD":{"v":1.3435}},
{"d":"2017-01-04","FXUSDCAD":{"v":1.3315}},
{"d":"2017-01-05","FXUSDCAD":{"v":1.3244}},
{"d":"2017-01-06","FXUSDCAD":{"v":1.3214}},
{"d":"2017-01-09","FXUSDCAD":{"v":1.3240}},
{"d":"2017-01-10","FXUSDCAD":{"v":1.3213}}
]
}

To get the information we want, we need to iterate over the elements in the observations list and map the date (d) to the conversion rate (FXUSDCAD.v). Since this will create a list of single-element dictionaries, we'll also need to "add" (merge) them together.

To do this with jq, it looks like this:

1
2
3
4
curl -s "https://www.bankofcanada.ca/valet/observations/FXUSDCAD/json?start_date=2017-01-01&end_date=2017-01-10" |\
jq '
    [.observations[] | {(.d) : .FXUSDCAD.v}] | add
'
1
2
3
4
5
6
7
8
9
{
  "2017-01-02": null,
  "2017-01-03": 1.3435,
  "2017-01-04": 1.3315,
  "2017-01-05": 1.3244,
  "2017-01-06": 1.3214,
  "2017-01-09": 1.324,
  "2017-01-10": 1.3213
}

That first null entry where there was no data is going to cause problems later, so let's just delete it using the del function:

1
2
3
4
curl -s "https://www.bankofcanada.ca/valet/observations/FXUSDCAD/json?start_date=2017-01-01&end_date=2017-01-10" |\
jq '
    [.observations[] | {(.d) : .FXUSDCAD.v}] | add | del(.[] | nulls)
'
1
2
3
4
5
6
7
8
{
  "2017-01-03": 1.3435,
  "2017-01-04": 1.3315,
  "2017-01-05": 1.3244,
  "2017-01-06": 1.3214,
  "2017-01-09": 1.324,
  "2017-01-10": 1.3213
}

Now this may be good enough for most purposes, but it would be useful to compute some other statistics from this data. For example, we want to know the average exchange rate for the date range. Now that we have the data in an easy to use format, computing an average with jq is just a matter of passing the values to an add / length filter. For example:

1
2
3
4
curl -s "https://www.bankofcanada.ca/valet/observations/FXUSDCAD/json?start_date=2017-01-01&end_date=2017-01-10" |\
jq '
    [.observations[] | {(.d) : .FXUSDCAD.v}] | add | del(.[] | nulls) | add / length
'
1
1.327683333333333

We can now construct an object that has both the average, as well as all the data. Putting it all together we get:

1
2
3
4
5
6
7
8
curl -s "https://www.bankofcanada.ca/valet/observations/FXUSDCAD/json?start_date=2017-01-01&end_date=2017-01-10" |\
jq '
    [.observations[] | {(.d) : .FXUSDCAD.v}] | add | del(.[] | nulls) |
    {
        "average": (add / length),
        "values": .
    }
'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "average": 1.327683333333333,
  "values": {
    "2017-01-03": 1.3435,
    "2017-01-04": 1.3315,
    "2017-01-05": 1.3244,
    "2017-01-06": 1.3214,
    "2017-01-09": 1.324,
    "2017-01-10": 1.3213
  }
}

And that's it! Hopefully you found this useful, if not for it's stated purpose of retrieving exchange rates, then at least for getting more familiar with jq. It's pretty much the best tool out there when it comes to manipulating JSON on the command line.

Appendix

Date ranges

  • The server will only ever return data from 2017-01-03 and onwards. If the start range is before that, it doesn't return an error, it just doesn't return any data for those dates.
  • If the end date isn't specified, the server assumes the current date.
  • There doesn't seem to be any limit on the amount of data retrieved

Currency codes

A list of codes can be easily scraped from the lookup page. The command and its result are below for reference.

1
curl -s "https://www.bankofcanada.ca/rates/exchange/daily-exchange-rates-lookup/" | grep -Eo '"FX......".*<'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"FXAUDCAD">Australian dollar<
"FXBRLCAD">Brazilian real<
"FXCNYCAD">Chinese renminbi<
"FXEURCAD">European euro<
"FXHKDCAD">Hong Kong dollar<
"FXINRCAD">Indian rupee<
"FXIDRCAD">Indonesian rupiah<
"FXJPYCAD">Japanese yen<
"FXMYRCAD">Malaysian ringgit<
"FXMXNCAD">Mexican peso<
"FXNZDCAD">New Zealand dollar<
"FXNOKCAD">Norwegian krone<
"FXPENCAD">Peruvian new sol<
"FXRUBCAD">Russian ruble<
"FXSARCAD">Saudi riyal<
"FXSGDCAD">Singapore dollar<
"FXZARCAD">South African rand<
"FXKRWCAD">South Korean won<
"FXSEKCAD">Swedish krona<
"FXCHFCAD">Swiss franc<
"FXTWDCAD">Taiwanese dollar<
"FXTHBCAD">Thai baht<
"FXTRYCAD">Turkish lira<
"FXGBPCAD">UK pound sterling<
"FXUSDCAD">US dollar<
"FXVNDCAD">Vietnamese dong<

© Carey Metcalfe. Built using Pelican. Theme is subtle by Carey Metcalfe. Based on svbhack by Giulio Fidente.