Skip to content

Instantly share code, notes, and snippets.

@deckar01
Last active November 26, 2015 01:24
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save deckar01/6d9b76bdef21eaab0568 to your computer and use it in GitHub Desktop.
Save deckar01/6d9b76bdef21eaab0568 to your computer and use it in GitHub Desktop.
Rooting the Transcend WiFi SD card by injecting commands into the wifi channel config

Other languages:

Rooting the Transcend WiFi SD card

by injecting commands into the wifi channel config

sd

This exploit requires opening the "Files" page of the card's web interface and escaping to the root of the file system.

http://192.168.11.254/cgi-bin/file_list.pl?dir=%2Fwww%2Fsd%2F..%2F..

http://haxit.blogspot.com/2013/08/hacking-transcend-wifi-sd-cards.html

/www/cgi-bin contains scripts that can be executed with HTTP requests. The link mentioned above exploits the fact that the perl scripts use unescaped request parameters in a system command that sets the login credentials. Lets see if we can find an attack vector that doesn't corrupt the configuration state.

I downloaded the contents of the cgi-bin directory and decided to construct a regular expression that could identify vulnerable system calls. I ended up with:

Searching 16 files for "`[^`\n]*\$[A-Z_]+[^`\n]*`" (regex, case sensitive)

/www/cgi-bin/kcard_edit_config.pl:
    5  my $WiFi_channel;
    6  my $Host_Switch_LEN=0;
    7: #`$WPA2_Key_backup`;
    8  sub wireless_scan{
    9      if(`$iwlist_scan`){

/www/cgi-bin/kcard_edit_config_insup.pl:
    5  my $WiFi_channel;
    6  my $Host_Switch_LEN=0;
    7: #`$WPA2_Key_backup`;
    8  sub wireless_scan{
    9      if(`$iwlist_scan`){

/www/cgi-bin/kcard_save_config.pl:
   80     close(CONFIG_FILE);   
   81     if (length($LOGIN_USR) >= 5  && length($LOGIN_PWD) >= 3) {
   82: 		`$update_auth $LOGIN_USR $LOGIN_PWD > /mnt/mtd/config/ia.passwd`
   83     }
   84  #`$auth_to_mtd`;
   ..
  224  {
  225  #system("cp /etc/wsd.conf /etc/wsd_backup.conf");
  226: #`$WPA2_Key_backup`;
  227  open(FHD, ">/mnt/mtd/config/hostapd.conf") or die("Could not open hostapd.conf");
  228  print FHD <<EndText;

/www/cgi-bin/kcard_save_config_insup.pl:
   96     close(CONFIG_FILE);   
   97     if (length($LOGIN_USR) >= 5  && length($LOGIN_PWD) >= 3) {
   98: 		`$update_auth $LOGIN_USR $LOGIN_PWD > /mnt/mtd/config/ia.passwd`
   99     }
  100  #`$auth_to_mtd`;
  ...
  252  {
  253  #system("cp /etc/wsd.conf /etc/wsd_backup.conf");
  254: #`$WPA2_Key_backup`;
  255  open(FHD, ">/mnt/mtd/config/hostapd.conf") or die("Could not open hostapd.conf");
  256  print FHD <<EndText;

/www/cgi-bin/kcard_status.pl:
    5  my $Host_Channel = &Channel();
    6  my $WPA2_Channel = "/bin/iwconfig $HWDEV channel $Host_Channel"; 
    7: `$WPA2_Channel`;
    8  my $iwlist_channel="/bin/iwlist $HWDEV channel > /tmp/iwlist_channel.txt";
    9  my $dhcp_list="/usr/bin/dumpleases -f /var/lib/misc/udhcpd.lease > /tmp/dhcpd.lease";

7 matches across 5 files

The strategy was to only look at the injected variables that had upper case letter in their names. The variables that were all lowercase seemed to be hard coded strings, so removing them narrowed things down quite a bit.

###/www/cgi-bin/kcard_status.pl

my $Host_Channel = &Channel();
my $WPA2_Channel = "/bin/iwconfig $HWDEV channel $Host_Channel"; 
`$WPA2_Channel`;

lines 5-7

This looks interesting. A variable at the end of a system command.

sub Channel{
    open(my $CONFIG_FILE, "<", "/etc/wsd.conf") or die("Could not open wsd.conf");
    my($Host_Channel);
    while( my $line = <$CONFIG_FILE>){
        chomp($line);
           if($line =~ /Channel : (.*)/){
            $Host_Channel = $1;
           }
   }
   close(CONFIG_FILE);      
   return ($Host_Channel);
}

lines 186-197

Everything after the colon? That should do.

I can’t write to the config file directly, but surely I can change the WiFi Channel in the settings somewhere.

/cgi-bin/kcard_edit_config_insup.pl

Settings

No WiFi channel input…

Settings hidden inputs

So many hidden inputs!

/www/cgi-bin/kcard_save_config_insup.pl

foreach $NameValue (@NameValuePairs) {
  ($Name, $Value) = split (/=/, $NameValue);
  $Value =~ tr/+/ /;
  $Value =~ s/%([\dA-Fa-f][\dA-Fa-f])/ pack ("C",hex ($1))/eg;
  $Form{$Name} = $Value;
}

lines 132-137

Manually parse those query parameters...

$CHANNEL_SET = $Form{Channel_Num};

line 154

Assign the channel to a variable...

print CONFIG_FILE "Channel : $CHANNEL_SET\n”;

line 60

Slap a new line on that bad boy and flush it to the disk!

All we have to do is inject a script into the end of the wifi channel, POST it to http://92.168.11.254/cgi-bin/kcard_save_config_insup.pl, and GET http://92.168.11.254/cgi-bin/card_status.pl any time we want the script to execute.

Time to upgrade to a full copy of busybox and get this show on the road.

Conclusion

Without physical access to the device we have gained root access to the filesystem. Future research will be focused on bypassing the admin credentials and WiFi key.

Contact

If you find a typo, some ambiguity, or a juicy new hack feel free to leave a comment below.

If you would like to contact me directly send an email to:

Jared Deckard (jared.deckard+sdwifi@gmail.com)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment