Jump to content

Sandisk Wireless Connect 16G Flash Drive


Bilgus

Recommended Posts

I Picked up the Sandisk Wireless Connect 16G at w.mart for $20 figured it would be fun to hack

Processor: Marvell: 88wm302 (per FCC filing pictures)

 

I tried pulling apart the firmware, comparing between the three firmware files I was able to find (2034) (2038) (2050)

I was able to narrow the checksum down to a 96 byte area of the file but I just can't seem to crack the encoding maybe (3-way cipher??)

I do know the version number is checksummed with the value in decimal converted to hex
 

Quote

 

0802 = 2050

07EE = 2038

07F2 = 2034

 

 

I finally gave up and took the device apart, there is a SD card inside the device.

Taking the card out and putting it into a card reader I was able to see the device had (2) 16mb uninitialized partitions

the second of them had the device firmware in it.

While the card is within the Connect device this second partition is not accessible.

File size is stored at the beginning of every file but I have yet to find the drive table so it must be a custom filesystem.

 

I have edited the file 'sort.js' to allow index redirection to my own file

I'll be adding this once i get it finished and simplified the process a bit.

 

Notes:

settings.xml is accessible from root 'sandisk.com/settings.xml'

the device uses a http.post method to rewrite the xml file,

I expanded this to try and re-write the scripts but got reply of 'Bad Request'

/myconnect/files/ and /myconnect/wfd/ are the same directory

javascript is in /static/js/

the media javascript is in /static/mejs

css is in /static/css/ 

Index.html seems to be auto generated from a templatesort.js fills the page

Link to comment
Share on other sites

 

So first we will talk about how to restore the device

Lets face it, that is the most important part to any good device hack;

Plus It'll be similar to how you can put the modified firmware on the device

 

 

First, lets make an image of the device
 

Windows users:

You will need some drive image software that will do RAW read and write,

I Found HDDGURU: HDDRawCopy1.10 can do the job

http://hddguru.com/software/HDD-Raw-Copy-Tool/

When you make your image backup don't compress it if you plan to change the firmware as you will have to edit this image

HxD hex editor supports editing drive images and is a pretty good great free hex editor (RC2.0) https://mh-nexus.de/downloads/HxDSetup.zip

once you are done editing you can put your patched firmware back with HDDRawCopy

I have made a compressed Restore image Here:

http://www.mediafire.com/file/ej65cqjt518b1f5/Sandisk_Connect_Restore_Blank.imgc
The image is compressed with HDDRawCopy can handle it natively since it made it, Linux users probably won't be able to use it (see below)

 

Linux Users:

you should know dd

Active@ Disk Editor can edit the image or directly edit the drive http://www.disk-editor.org/ beware it is quite finicky but usable

I have made a gz compressed Restore image Here:

http://www.mediafire.com/file/ayzy2w8rh203zmp/Sandisk_Connect_Restore_Blank.img.gz

 

Notes:

You will need to open your drive to remove the SD card;

We don't have access to the second hidden partition while it is in the wireless flash drive

Insert a card into the back just behind the sandisk logo then work your way around each side to open the snaps

finally slide the top forward to remove it from the usb plug

 

 

Link to comment
Share on other sites

2 hours ago, kdodge said:

is the Sandisk Wireless Connect, act as an access point, and have a web interface for configuration?

Yes, it is a wifi access point for up to 3 devices, with configuration

I saw where someone said it could be put on another network but I have yet to make that work

Link to comment
Share on other sites

I have one of those and fancied the idea to couple that with a pineapple.  Something went bad on it and can't find the storage partition, I need to reformat it.

Link to comment
Share on other sites

14 minutes ago, Spoonish said:

I have one of those and fancied the idea to couple that with a pineapple.  Something went bad on it and can't find the storage partition, I need to reformat it.

You will need that recovery image if it is a problem with the device code otherwise in windows just reformat with FAT 32 and that will fix the storage partition

Link to comment
Share on other sites

Ok so some progress, I figured out the file structure in the firmware and made a little AutoIt script to extract the files

I have yet to find where the file names and extensions are stored but I deduced all but the binary one, the .unk file in all the firmwares is a binary file and is the same in (2050) and (2038) but different between (2050) and (2034)

Also there is a curious Text file with hex bytes in it I'd really like to know what it is for..

Do be aware if you are pointing this thing at a full disk image (16- 32 GB) you are going to be waiting for a long while..

See updated file extraction script below

Edited by Bilgus
remove old code
Link to comment
Share on other sites

Here is an updated script with more robust header searching and the ability to set an offset on files larger than 16 mb and the ability to resume on error

 

Capture.thumb.PNG.ea8a7aaf7ba960a9eedcfa66af978a54.PNG

#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>
#include <AutoItConstants.au3>
#include <String.au3>
#include <Array.au3> ; Required for _ArrayDisplay() only.
#include <File.au3> ;FileWriteLog


Local $sFileOpenDialog = FileOpenDialog("Choose Firmware File", _
		@ScriptDir, "All (*)|Disk Images (*.img)|Firmware (*.df3)", 3)

Local $sLogPath = $sFileOpenDialog & ".log"
Local $sWritePath = $sFileOpenDialog & "_Files\"
Local $sMessage = ""
Local Const $sSplashTitle = "Extract Connect Files"
Global $iStartPos = 0

While ($iStartPos > -1)
	$iStartPos = ExtractConnectFiles($sFileOpenDialog, $sLogPath, $sWritePath, $iStartPos)
WEnd


Func _StringEqualSplit($sString, $iNumChars)
	If (Not IsString($sString)) Or $sString = "" Then Return SetError(1, 0, 0)
	If (Not IsInt($iNumChars)) Or $iNumChars < 1 Then Return SetError(2, 0, 0)
	Return StringRegExp($sString, "(?s).{1," & $iNumChars & "}", 3)
EndFunc   ;==>_StringEqualSplit


Func _Exit($hLogFile, $hBinaryFileOpen)
	$iStartPos = -1
	Sleep(3000)
	FileClose($hLogFile)
	FileClose($hBinaryFileOpen)
	Exit
EndFunc   ;==>_Exit


Func FindStorageHeader($sFilePath, $iFileSz, $iStartPos) ;FF FF FF FF 00 00 [00 00 SZ BY] .. [00 00 00 01]
	Local $i, $hBinaryFileOpen = FileOpen($sFilePath, 0 + 16)
	Local $sHexSearch = "0xFFFFFFFF0000"
	Local $iSearchSz = Int((StringLen($sHexSearch) - 2) / 2)
	Local $iFileSzKb = Int($iFileSz / 1024)
	Local $iRetPos = -1
	Local $iFileHeaderLen = 0
	If $hBinaryFileOpen = -1 Then
		MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.")
		Return -1
	EndIf
	If ($iFileSzKb > 17000) Then ; Probably a diskimage let user decide where to search
		$iStartPos = InputBox("Large File, Search from a different offset?", "Enter the offset you would like to search from [0 -" _
				 & $iFileSz - $iSearchSz - 1 & "]", $iStartPos, Default, -1, -1, Default, Default, 30)
	EndIf
	For $i = $iStartPos To $iFileSz - $iSearchSz - 1
		$iFileProgress = Int(($i + 1) / 1024)
		If ($iFileProgress = ($i + 1) / 1024) Then
			If (0 = ControlSetText($sSplashTitle, "", "Static1", $sMessage & _
					"Searching for Storage Header... (" & $iFileProgress & " / " & $iFileSzKb & ") ")) Then ExitLoop

		EndIf
		FileSetPos($hBinaryFileOpen, $i, 0)
		$Data = FileRead($hBinaryFileOpen, $iSearchSz) ; ;FF FF FF FF 00 00
		If ($Data = $sHexSearch) Then
			$iFileHeaderLen = Dec(ExtractHexBytes($hBinaryFileOpen, $i + 4, 4), 1) ; [00 00 SZ BY] extract len in hex convert to 32 bit decimal
			$iRetPos = $i
			If (1 = Dec(ExtractHexBytes($hBinaryFileOpen, $i + 8, 4), 1)) Then ExitLoop ;.. [00 00 00 01]
		EndIf
	Next
	FileClose($hBinaryFileOpen)
	Return $iRetPos
EndFunc   ;==>FindStorageHeader


Func ExtractHexBytes($hBinaryFileOpen, $iStart, $iBytes)
	Local $iOldPos = FileGetPos($hBinaryFileOpen)
	If @error Or $hBinaryFileOpen = -1 Then
		MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.")
		Return ""
	EndIf

	FileSetPos($hBinaryFileOpen, $iStart, 0) ;Offset from beginning
	Global $Data = FileRead($hBinaryFileOpen, $iBytes)
	FileSetPos($hBinaryFileOpen, $iOldPos, 0) ;Restore original position
	Return StringTrimLeft(String($Data), 2) ;Remove 0x from beginning
EndFunc   ;==>ExtractHexBytes


Func FileTypeExtension($iFileType)
	Local Const $aFileExt[12][2] = [[0, ".UNK"], [1, ".UNK"], _
			[14, ".swf"], [15, ".zip"], [25, ".gif"], [27, ".png"], _
			[28, ".xml"], [33, ".css"], [35, ".html"], [36, ".JS"], [37, ".txt"]]

	Local $i = 0
	Local $sExt = $aFileExt[0][1]
	For $i = 0 To UBound($aFileExt) - 1
		If ($aFileExt[$i][0] = $iFileType) Then
			Local $sExt = $aFileExt[$i][1]
			ExitLoop
		EndIf
	Next
	Return $sExt
EndFunc   ;==>FileTypeExtension


Func ExtractConnectFiles($sFilePath, $sLogPath, $sWritePath, $iStartPos)
	Local $hLogFile = FileOpen($sLogPath, 1)
	Local $iFileSz = FileGetSize($sFilePath)
	Local $i = 0, $j = 0
	Local $sLogMsg = "Extract Connect Files Started" & @CRLF & "Sz: " & $iFileSz & " bytes, Path: " & $sFilePath & @CRLF

	$sMessage = $sLogMsg
	SplashTextOn($sSplashTitle, $sMessage & _
			"Searching for Storage Header...", -1, 200, -1, 18, _
			BitOR($DLG_TEXTLEFT, $DLG_NOTONTOP, $DLG_MOVEABLE), "", 10)
	Sleep(1000)
	_FileWriteLog($hLogFile, $sLogMsg)
	$iStartPos = FindStorageHeader($sFilePath, $iFileSz, $iStartPos)
	If ($iStartPos > -1) Then
		$sLogMsg = "Storage Header Found @ " & String(Hex($iStartPos))
		$sMessage = $sMessage & $sLogMsg & @CRLF
		_FileWriteLog($hLogFile, $sLogMsg)
	Else
		$sLogMsg = "!Error! Storage Header Not Found!"
		_FileWriteLog($hLogFile, $sLogMsg)
		ControlSetText($sSplashTitle, "", "Static1", $sMessage & @CRLF & $sLogMsg & @CRLF & "Exiting...")
		_Exit($hLogFile, -1)
	EndIf
	ControlSetText($sSplashTitle, "", "Static1", $sMessage)
	Local $hBinaryFileOpen = FileOpen($sFilePath, 0 + 16)
	If $hBinaryFileOpen = -1 Then
		MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.")
		_Exit($hLogFile, -1)
	EndIf
	Local $iFileHeaderLen = Dec(ExtractHexBytes($hBinaryFileOpen, $iStartPos + 4, 4), 1) ;extract len in hex convert to 32 bit decimal
	If ($iFileHeaderLen > 600 Or $iFileHeaderLen < 200) Then
		Local $iCancelTryContinue = MsgBox(16 + 6, "Error", _
				"Header Length is out of range continue to force or try again to find a new header", 30)

		If ($iCancelTryContinue = 2) Then
			_Exit($hLogFile, -1)
		ElseIf ($iCancelTryContinue = 10 Or $iCancelTryContinue = -1) Then ;tryagain or timeout
			Return $iStartPos + 1
		EndIf
	EndIf
	Local $sFileHeader = ExtractHexBytes($hBinaryFileOpen, $iStartPos + 8, $iFileHeaderLen)
	$sLogMsg = "FileHeader Sz: " & $iFileHeaderLen & " bytes" & @CRLF & "Data:[" & $sFileHeader & "]"
	$sMessage = $sMessage & "File Header Found! Sz: " & $iFileHeaderLen & " bytes" & @CRLF
	ControlSetText($sSplashTitle, "", "Static1", $sMessage)
	_FileWriteLog($hLogFile, $sLogMsg)
	Local $iElemsPer = 3 ; Each file has [Index, offset, Type]
	Local $aS = _StringEqualSplit($sFileHeader, 8)
	If IsArray($aS) Then
		Local $iFileCount = Int(UBound($aS) / $iElemsPer)
		Local $aFileData[$iFileCount][4] ;We will store the file data as [FileIndex, FileType, FileOffset, SzBytes]
		$j = 0 ;
		;_ArrayDisplay($aS, "Raw File Header", Default, 32 + 64, Default, "", Default, 0xDDFFDD)
		For $i = 0 To UBound($aS) - 1 Step $iElemsPer
			$aFileData[$j][0] = Dec($aS[$i + 0])
			$aFileData[$j][1] = FileTypeExtension(Dec($aS[$i + 2]))
			$aFileData[$j][2] = $iStartPos + Dec($aS[$i + 1])
			Local $iFileHeaderOffset = Dec(ExtractHexBytes($hBinaryFileOpen, $aFileData[$j][2], 4), 1)
			If ($iFileHeaderOffset = $aFileData[$j][0]) Then ;check header at offset see if it matches
				$aFileData[$j][3] = Dec(ExtractHexBytes($hBinaryFileOpen, $aFileData[$j][2] + 4, 4), 1) ;extract len in hex convert to 32 bit decimal
			Else

				$aFileData[$j][3] = "BAD HEADER"
				Local $iCancelTryContinue = MsgBox(16 + 6, "Error", _
						"File Has a bad Header continue or try again to find a new storage header", 30)

				If ($iCancelTryContinue = 2) Then
					_Exit($hLogFile, $hBinaryFileOpen)
				ElseIf ($iCancelTryContinue = 10 Or $iCancelTryContinue = -1) Then ;tryagain or timeout
					Return $iStartPos + 1
				EndIf

			EndIf
			$sLogMsg = "File Index: " & $aFileData[$j][0] & " File Type: " & _
					$aFileData[$j][1] & " File Offset: 0x" & Hex($aFileData[$j][2], 8) & _
					" File Size Bytes:" & $aFileData[$j][3]

			_FileWriteLog($hLogFile, $sLogMsg)
			$j = $j + 1
			If ($j > $iFileCount) Then
				MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading FileData")
			EndIf
		Next
		_ArrayDisplay($aFileData, $sSplashTitle & " Found", Default, 16 + 32 + 64, Default, _
				"Index |Type |Offset |Bytes ", 500, 0xDDFFDD)

		$sMessage = $sMessage & "Extracting Files: " & $sWritePath & @CRLF
		If (7 = MsgBox(4 + 32 + 256, "Extract Files?", "Press Yes to Extract files to" & @CRLF & $sWritePath)) Then
			_Exit($hLogFile, $hBinaryFileOpen)
		EndIf
		SplashTextOn($sSplashTitle, $sMessage, -1, 200, -1, 18, BitOR($DLG_TEXTLEFT, $DLG_NOTONTOP, $DLG_MOVEABLE), "", 10)

		For $i = 0 To $iFileCount - 1
			If ($aFileData[$i][3] <> "BAD HEADER") Then
				ControlSetText($sSplashTitle, "", "Static1", $sMessage & " (" & $i + 1 & "/" & $iFileCount & ") " & _
						$aFileData[$i][0] & $aFileData[$i][1])

				FileSetPos($hBinaryFileOpen, ($aFileData[$i][2]) + 8, 0)
				Local $hBinaryFileWrite = FileOpen($sWritePath & $aFileData[$i][0] & $aFileData[$i][1], 2 + 8 + 16)
				If @error Or $hBinaryFileOpen = -1 Then
					MsgBox($MB_SYSTEMMODAL, "", "An error occurred trying to write the file." & @CRLF & _
							$sWritePath & $aFileData[$i][0] & $aFileData[$i][1])

					ExitLoop
				EndIf
				FileWrite($hBinaryFileWrite, FileRead($hBinaryFileOpen, $aFileData[$i][3]))
				FileClose($hBinaryFileWrite)

			EndIf
		Next

	EndIf

	_Exit($hLogFile, $hBinaryFileOpen)
EndFunc   ;==>ExtractConnectFiles

 

Edited by Bilgus
Forum wouldn't let me upload images till after saving once??
Link to comment
Share on other sites

  • 2 months later...

I've pretty much stopped work on this, I was able to edit the firmware on the device to allow a redirect to my own index.html on page load

Unfortunately it seems the device has the web address hardcoded to www.sandisk.com/myconnect

and I'm pretty sure its in the actual rom because I couldn't find it in the firmware.

I was more hoping to be able to redirect any address to my own pages but if you are just looking for that (limited) functionality I've included instructions

 

I'd recommend looking into the zsin devices if you need the form factor https://wiki.hackerspace.pl/projects:zsun-wifi-card-reader

 

or just get one of those small openwrt micro routers which is the route I took

 

You will have to use a hex editor on the image you pull from the device, use the file extractor abovet to get a little context into the file you need to edit

find the first instance of this:


var resizeTimer;.function doResize() {clearTimeout(resizeTimer); if(lastWidth != $(window).width()) 

{window.location.reload();}}


then search backwards from that point for:
// Finally, protect remaining links with a click function that will mute the audio player if it is playing.

// and pause if we leave the page.

Free up enough space for our redirect by deleting the comments....

Shift the whole file up and finally
place this just before 'AirStash.initializePage();


window.onresize = function() {
    clearTimeout(resizeTimer);
    

resizeTimer = setTimeout(doResize, 300);

}
'

Note the text below is to the end of the file so don't duplicate 'AirStash.initializePage();


window.onresize = 

function() {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(doResize, 300);

}
'

TEXT:

function elm_hide(h){
var e = document.getElementsByTagName("*");for(var i = 0; i < e.length; i++){e

[i].style.visibility = h;}
}
function ld_pg(u, cb){
if(window.location.search == ''){elm_hide("hidden");}
var r = new 

XMLHttpRequest();
var s = window.location.search;
r.open('GET',u, true);
r.onreadystatechange=function(e){if(r.readyState 

== 4 && (r.status == 200) && (s == '' || s == '?dbg')){$('html').html(r.responseText);if(s == '?dbg'){console.log

('Redirect old:' + window.location.href + ' new:' + u);console.log("<html>" + $("html").html() + "</html>");}

r.onreadystatechange=null;return;} else if (r.status != 200) {//Continue loading page as normal
elm_hide("visible");cb();}
}
r.send();
}
ld_pg('/wfd/.web/index.html', function(){AirStash.initializePage

();window.onresize = function() {clearTimeout(resizeTimer);resizeTimer = setTimeout(doResize, 300);}}

TEXT IN HEX:
0A66756E6374696F6E20656C6D5F686964652868297B0A7661722065203D20646F63756D656E742E676574456C656D656E747342795461674E616D

6528222A22293B0A09666F72287661722069203D20303B2069203C20652E6C656E6774683B20692B2B297B655B695D2E7374796C652E7669736962

696C697479203D20683B7D0A7D0A66756E6374696F6E206C645F706728752C206362297B0A69662877696E646F772E6C6F636174696F6E2E736561

726368203D3D202727297B656C6D5F68696465282268696464656E22293B7D0A7661722072203D206E657720584D4C487474705265717565737428

293B0A7661722073203D2077696E646F772E6C6F636174696F6E2E7365617263683B0A722E6F70656E2827474554272C752C2074727565293B0A72

2E6F6E726561647973746174656368616E67653D66756E6374696F6E2865297B0A09696628722E72656164795374617465203D3D20342026262028

722E737461747573203D3D2032303029202626202873203D3D202727207C7C2073203D3D20273F6462672729297B0A090924282768746D6C27292E

68746D6C28722E726573706F6E736554657874293B0A090969662873203D3D20273F64626727297B0A090909636F6E736F6C652E6C6F6728275265

646972656374206F6C643A27202B2077696E646F772E6C6F636174696F6E2E68726566202B2027206E65773A27202B2075293B0A090909636F6E73

6F6C652E6C6F6728223C68746D6C3E22202B2024282268746D6C22292E68746D6C2829202B20223C2F68746D6C3E22293B0A09097D0A0909722E6F

6E726561647973746174656368616E67653D6E756C6C3B0A090972657475726E3B0A097D20656C73652069662028722E73746174757320213D2032

303029207B0A09092F2F436F6E74696E7565206C6F6164696E672070616765206173206E6F726D616C0A0909656C6D5F6869646528227669736962

6C6522293B0A0909636228293B0A097D0A7D0A722E73656E6428293B0A7D0A6C645F706728272F7766642F2E7765622F696E6465782E68746D6C27

2C2066756E6374696F6E28297B0A0941697253746173682E696E697469616C697A655061676528293B0A0977696E646F772E6F6E726573697A6520

3D2066756E6374696F6E2829207B0A0909636C65617254696D656F757428726573697A6554696D6572293B0A0909726573697A6554696D6572203D

2073657454696D656F757428646F526573697A652C20333030293B0A097D0A097D0A0A
Link to comment
Share on other sites

  • 4 weeks later...
  • 4 weeks later...
On 11/1/2017 at 10:35 PM, Forgiven said:

I'm pretty sure that post is about the wireless media drive, a ~3x3" brick.

I wasn't able to get a telenet session or even any open ports besides 80 on the wireless flash drive ( a 1x3" boxy thumb drive)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...