AndreasFagschlunger / O2Xfs

Java API for accessing CEN/XFS API, EMV Level 2 Kernel
47 stars 28 forks source link

what is Different between CASH_IN and OPEN_SHUTTER-CLOSE_SHUTTER #43

Closed azdafirmansyah closed 7 years ago

azdafirmansyah commented 7 years ago

Hi All,

Please correct me if i'm wrong,

  1. How to get result from 'wfsResultCashIn' ?
  2. which one is correct way ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

Read the interface specification for details about the commands:

ftp://ftp.cenorm.be/CWA/CEN/WS-XFS/CWA15748/CWA15748-15-2008-July.pdf

OPEN_SHUTTER and CLOSE_SHUTTER will basically do what you expect, opening or closing the shutter. The Capabilities3.isShutterControl() method indicates if the shutter is controlled implicitly by the service provider. If isShutterControl() returns false, the shutter must be explicitly controlled by the application.

As mentioned, the CIM interface specification gives you examples of some transaction flows in chapter 7. For example, the transaction flow for a OK transaction with explicit shutter control would be something like this:

A CASH_IN command will produce lots of execute and service events you must deal with, but here is some pseudo code which should give you clues:

        CimService cimService = ...
        // CASH_IN_START, etc. ...
        XfsExecuteCommand<CimExecuteCommand> executeCommand = new XfsExecuteCommand<CimExecuteCommand>(cimService,
                CimExecuteCommand.CASH_IN);
        cimService.addCimServiceListener(new CimServiceListener() {

            public void onItemsInserted() ...
            public void onItemsTaken() ...
            public void onItemsPresented() ...
        });
        executeCommand.execute(new XfsEventNotification() {

            @Override
            public void fireOperationCompleteEvent(WFSResult wfsResult) {
                String method = "fireOperationCompleteEvent(WFSResult)";
                try {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug(method, "wfsResult=" + wfsResult);
                    }
                    XfsException.throwFor(wfsResult.getResult());
                    NoteNumberList3 noteNumberList3 = new NoteNumberList3(wfsResult.getResults());
                    noteNumberList3 = new NoteNumberList3(noteNumberList3); // copy for later use
                    System.out.println(noteNumberList3);
                } catch (XfsException e) {
                    e.printStackTrace();
                } finally {
                    XfsServiceManager.getInstance().free(wfsResult);
                }
            }

            @Override
            public void fireIntermediateEvent(WFSResult wfsResult) {
                String method = "fireIntermediateEvent(WFSResult)";
                if (LOG.isDebugEnabled()) {
                    LOG.debug(method, "wfsResult=" + wfsResult);
                }
                try {
                    CimMessage cimMessage = wfsResult.getEventID(CimMessage.class);
                    switch (cimMessage) {
                    case EXEE_CIM_CASHUNITERROR:
                        /* TODO */ break;
                    case EXEE_CIM_INPUT_P6:
                        /* TODO */ break;
                    case EXEE_CIM_INPUTREFUSE:
                        /* TODO */ break;
                    case EXEE_CIM_NOTEERROR:
                        /* TODO */ break;
                    case EXEE_CIM_SUBCASHIN:
                        /* TODO */ break;
                    case EXEE_CIM_INFO_AVAILABLE:
                        /* TODO */ break;
                    case EXEE_CIM_INSERTITEMS:
                        /* TODO */ break;
                    default:
                        throw new IllegalArgumentException(cimMessage.toString());
                    }
                } finally {
                    XfsServiceManager.getInstance().free(wfsResult);
                }
            }
        });

ATTENTION: For example new NoteNumberList3(wfsResult.getResults()) create a java object from native memory. The call XfsServiceManager.free(WFSResult) will release this memory. So if you want to use this information outside of the event processing method, use the copy constructor. Otherwise you may end up accessing already freed memory and your JVM crashes.

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hello @AndreasFagschlunger,

I follow your code and get the following error : java.lang.NullPointerException: Pointer points to NULL at at.o2xfs.win32.Pointer.buffer(Pointer.java:84) at at.o2xfs.win32.Type.assignBuffer(Type.java:44) at at.o2xfs.xfs.cim.v3_00.NoteNumberList3.(NoteNumberList3.java:50) at com.syb.test.TestApp$2.fireOperationCompleteEvent(TestApp.java:181)

but wfsResult.getResult() is nut null.

Any suggest ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Try System.out.println(wfsResult.getResults()), the object Pointer may not be null, but the address it's pointing to is likely to point to NULL. This is also valid according to the specification:

If the whole input was refused then this parameter will be NULL and one or more WFS_EXEE_CIM_INPUTREFUSE events will be generated.

So check against a (native) NULL-Pointer:

if(Pointer.NULL.equals(wfsResult.getResults())) ...
azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger ,

I try the following OK Transaction flow in doc. But still cannot get event any item Inserted.

please review my code : https://drive.google.com/file/d/0B3NRikF5MB_2ZFk3c3h4MTBwc3c/view?usp=sharing

I just want to try:

  1. Open shutter
  2. Insert Money
  3. Close Shutter
  4. Cash Count
  5. Deposit

Please advice.

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

The event handling must be implemented like in CdmService.fireServiceEvent(WFSResult), of course with the right CIM events. Also notice, SRVE_CIM_ITEMSINSERTED is only fired if Capabilities3.isItemsInsertedSensor() returns true. Otherwise the customer has to confirm completion (e.g., press button) to continue transaction with CASH_IN command.

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

I still get false while check the value of Capabilities3.isItemsInsertedSensor(). I do check the value in fireIntermediateEvent(WFSResult wfsResult) and fireOperationCompleteEvent function

Capabilities3 capabilities3 = new Capabilities3(wfsResult.getResults()); System.out.println(capabilities3.isItemsInsertedSensor());

Also get return EXEE_CIM_INPUTREFUSE from CimMessage

CimMessage cimMessage = wfsResult.getEventID(CimMessage.class);

Here is my snippet code :

public void fireIntermediateEvent(WFSResult wfsResult) { Capabilities3 capabilities3 = new Capabilities3(wfsResult.getResults()); System.out.println(capabilities3.isItemsInsertedSensor());

What I do in this step are :

Please advice.

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

What does Capabilities3.isShutterControl return? And if Capabilities3.isItemsInsertedSensor() returns false, you have to wait for a user interaction after CASH_IN_START, e.g.:

        System.out.println("Please insert money, press ENTER to continue...");
        new Scanner(System.in).nextLine();
        System.out.println("Executing CASH_IN ...");

And this is dangerous:

public void fireIntermediateEvent(WFSResult wfsResult) {
Capabilities3 capabilities3 = new Capabilities3(wfsResult.getResults());
System.out.println(capabilities3.isItemsInsertedSensor());

The fireIntermediateEvent method is called when an execute event occurs. This events may occur during execution of your command and are specific to the command you execute. So you have to check for the right CimMessage like in my example the last day. e.g.

try {
    CimMessage cimMessage = wfsResult.getEventID(CimMessage.class);
    switch (cimMessage) {
    case EXEE_CIM_CASHUNITERROR:
        /* TODO */ break;
    case EXEE_CIM_INPUT_P6:
        /* TODO */ break;
    case EXEE_CIM_INPUTREFUSE:
        Reason reason = new XfsWord<>(Reason.class, wfsResult.getResults());
        System.out.println("Reason for refusing part of the amount: " + reason);
        break;

Regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

Are you sure to wait for a user interaction after CASH_IN_START like you mention above ?

I print the result of EXEE_CIM_INPUTREFUSE, here is what i get : Reason for refusing part of the amount: INVALIDBILL

Can you review my code ? maybe something wrong in my code https://drive.google.com/file/d/0B3NRikF5MB_2V2dOMFJlb2haWkk/view?usp=sharing

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hi @azdafirmansyah

If Capabilities3.isItemsInsertedSensor() returns false, you have to wait until a customer inserts money and continues the transaction. This also means, no service event ITEMSINSERTED event will occur.

So your problem now is, that the cash in command works but reports INVALIDBILL? The description of INVALIDBILL is as follows:

Recognition of the items took place, but one or more of the items are invalid.

Is your ATM configured to accept test bills or do you use real bills? Can you test recognition with a vendor app? Unfortunately this issue lies beneath XFS and must be checked with your ATM vendor. You may find some information in the vendor logs. Or try to use real and dummy bills, maybe the configuration of your ATM is wrong.

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

If Capabilities3.isItemsInsertedSensor() returns false, you have to wait until a customer inserts money and continues the transaction. This also means, no service event ITEMSINSERTED event will occur. ---> I use CASH_IN command, when shutter open I put money inside shutter and than shutter will close automatically. I think when use this flow no need to wait customer inside money, because already do that

Is your ATM configured to accept test bills or do you use real bills? Can you test recognition with a vendor app? Unfortunately this issue lies beneath XFS and must be checked with your ATM vendor. You may find some information in the vendor logs. Or try to use real and dummy bills, maybe the configuration of your ATM is wrong. ---> Already success test using vendor tools with real money

Is it my code correct ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hi @azdafirmansyah

It's a bit strange, isItemsInsertedSensor should return true if the shutter closes one you inserted money. So the ATM waits a long time when you don't insert money but immediately closes if money is inserted? That should also mean you don't have to execute OPEN_SHUTTER command because the shutter is automatically opened during CASH_IN_START?

I can't access Google drive right now, since I'm behind a firewall. So I must check the code later. But it's strange you get INVALIDBILL when the vendor app does recognize the money. Try looking into vendor logs if you find some, maybe the leave a clue what's really wrong.

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

The shutter automatically open during CASH_IN command (not CASH_IN _START).

Here is what step I do :

Here is my code : ` CimService cimService = (CimService) xfsServiceManager.openAndRegister("CIM", CimService.class);

        cimService.addCimServiceListener(new CimServiceListener() {

            @Override
            public void onCimTellerInfoChanged(int tellerId) {
                // TODO Auto-generated method stub
                System.out.println("onCimTellerInfoChanged : " + tellerId);
            }

            @Override
            public void onCimShutterStatusChanged(
                    ShutterStatusChanged3_30 shutterStatusChanged) {
                // TODO Auto-generated method stub
                System.out.println("onCimShutterStatusChanged : "
                        + shutterStatusChanged);
            }

            @Override
            public void onCimSafeDoorOpen() {
                // TODO Auto-generated method stub
                System.out.println("onCimSafeDoorOpen : ");
            }

            @Override
            public void onCimSafeDoorClosed() {
                // TODO Auto-generated method stub
                System.out.println("onCimSafeDoorClosed : ");
            }

            @Override
            public void onCimPowerSaveChange(
                    PowerSaveChange3_10 powerSaveChange) {
                // TODO Auto-generated method stub
                System.out.println("onCimPowerSaveChange : "
                        + powerSaveChange);
            }

            @Override
            public void onCimMediaDetected(
                    Optional<ItemPosition3> itemPosition) {
                // TODO Auto-generated method stub
                System.out.println("onCimMediaDetected : " + itemPosition);
            }

            @Override
            public void onCimItemsTaken(at.o2xfs.xfs.cim.Position position) {
                // TODO Auto-generated method stub
                System.out.println("onCimItemsTaken : " + position);
            }

            @Override
            public void onCimItemsPresented() {
                // TODO Auto-generated method stub
                System.out.println("onCimItemsPresented : ");
            }

            @Override
            public void onCimItemsInsert(at.o2xfs.xfs.cim.Position position) {
                // TODO Auto-generated method stub
                System.out.println("onCimItemsInsert : " + position);
            }

            @Override
            public void onCimDevicePosition(
                    DevicePosition3_10 devicePosition) {
                // TODO Auto-generated method stub
                System.out.println("onCimDevicePosition : "+ devicePosition);
            }

            @Override
            public void onCimCountsChanged(CountsChanged3 countsChanged) {
                // TODO Auto-generated method stub
                System.out.println("onCimCountsChanged : " + countsChanged);
            }

            @Override
            public void onCimCashUnitThreshold(CashIn3 cashIn3) {
                // TODO Auto-generated method stub
                System.out.println("onCimCashUnitThreshold : " + cashIn3);
            }

            @Override
            public void onCimCashUnitInfoChanged(CashIn3 cashIn3) {
                // TODO Auto-generated method stub
                System.out.println("onCimCashUnitInfoChanged : " + cashIn3);
            }
        });

        Capabilities3 capabilities1 = cimService.getCapabilities();
        Set<at.o2xfs.xfs.cim.Position> pos = capabilities1.getPositions();
        Iterator itr = pos.iterator();
        while (itr.hasNext()) {
            at.o2xfs.xfs.cim.Position sPosition = (at.o2xfs.xfs.cim.Position)itr.next();
            String sName = sPosition.name();
            System.out.println(sName);
        }

        CashInStart3 cashInStart3 = new CashInStart3.Builder()
                .inputPosition(at.o2xfs.xfs.cim.Position.INFRONT)
                .outputPosition(at.o2xfs.xfs.cim.Position.OUTREAR).build();

        XfsExecuteCommand<CimExecuteCommand> cashInStartCommand = new XfsExecuteCommand<CimExecuteCommand>(
                cimService, CimExecuteCommand.CASH_IN_START, cashInStart3);
        WFSResult wfsResultCashInStart = null;
        try {
            wfsResultCashInStart = cashInStartCommand.call();
        } catch (XfsException e) {
            e.printStackTrace();
        } finally {
            if (wfsResultCashInStart != null) {
                xfsServiceManager.free(wfsResultCashInStart);
            }
        }

        XfsExecuteCommand<CimExecuteCommand> cashInCommand = new XfsExecuteCommand<CimExecuteCommand>(
                cimService, CimExecuteCommand.CASH_IN, cashInStart3);   
        cashInCommand.execute(new XfsEventNotification() {
            @Override
            public void fireOperationCompleteEvent(WFSResult wfsResult) {

                String method = "fireOperationCompleteEvent(WFSResult)";
                Capabilities3 capabilities3 = new Capabilities3(wfsResult.getResults());
                System.out.println(capabilities3.isItemsInsertedSensor());
                try {
                    XfsException.throwFor(wfsResult.getResult());
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                } finally {
                    XfsServiceManager.getInstance().free(wfsResult);
                }
            }

            @Override
            public void fireIntermediateEvent(WFSResult wfsResult) {
                try {
                    CimMessage cimMessage = wfsResult.getEventID(CimMessage.class);
                    switch (cimMessage) {
                    case EXEE_CIM_CASHUNITERROR:
                        /* TODO */break;
                    case EXEE_CIM_INPUT_P6:
                        /* TODO */break;
                    case EXEE_CIM_INPUTREFUSE:
                        XfsWord<Reason> reason = new XfsWord<>(Reason.class, wfsResult.getResults());                           
                        System.out.println("Reason for refusing part of the amount: " + reason.get().toString());                                                       
                        /* TODO */break;
                    case EXEE_CIM_NOTEERROR:
                        /* TODO */break;
                    case EXEE_CIM_SUBCASHIN:
                        /* TODO */break;
                    case EXEE_CIM_INFO_AVAILABLE:
                        /* TODO */break;
                    case EXEE_CIM_INSERTITEMS:
                        /* TODO */break;
                    default:
                        throw new IllegalArgumentException(cimMessage
                                .toString());
                    }
                } finally {
                    XfsServiceManager.getInstance().free(wfsResult);
                }
            }
        });`

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Ok, I mixed isShutterControl with isItemsInsertedSensor. Your ATM's shutter is implicitly control, therefore isShutterControl returns true. isItemsInsertedSensor will only inform you, if a inserted event is generated or not. What is obviously wrong is the code in fireOperationCompleteEvent:

public void fireOperationCompleteEvent(WFSResult wfsResult) {
    String method = "fireOperationCompleteEvent(WFSResult)";
    Capabilities3 capabilities3 = new Capabilities3(wfsResult.getResults());
    System.out.println(capabilities3.isItemsInsertedSensor());

The output parameter of CASH_IN is a pointer to WFSCIMNOTENUMBERLIST, where NULL is also possible. So something like this should work:

public void fireOperationCompleteEvent(WFSResult wfsResult) {
    String method = "fireOperationCompleteEvent(WFSResult)";
    if (LOG.isDebugEnabled()) {
        LOG.debug(method, "wfsResult=" + wfsResult);
    }
    try {
        XfsException.throwFor(wfsResult.getResult());
        if(Pointer.NULL.equals(wfsResult.getResults())) {
            System.out.println("Whole input was refused");
        } else {
            NoteNumberList3 noteNumberList = new NoteNumberList3(new NoteNumberList3(wfsResult.getResults()));
            System.out.println(noteNumberList);
        }
    } catch (XfsException e) {
        e.printStackTrace();                
    } finally {
        XfsServiceManager.getInstance().free(wfsResult);
    }
}

If your ATM recognizes some bills, you should get a NoteNumberList3 object.

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

Now I can recognize some bills in NoteNumberList3. I have few question :

  1. is it correct way or not if I execute CASH_IN_END command inside fireOperationCompleteEvent ? for example after get bill info :

    NoteNumber3[] noteNumber3 = noteNumberList.getNoteNumber(); .... XfsExecuteCommand cashEndCommand = new XfsExecuteCommand( cimService, CimExecuteCommand.CASH_IN_END, cashInStart3); WFSResult wfsResultCashEnd = null; try { wfsResultCashEnd = cashEndCommand.call(); ....

  2. When I execute CASH_IN_END command, I get "Waiting ..." from LOG like below

    2017-03-15 09:48:31,555 DEBUG [MessageHandler] at.o2xfs.xfs.XfsAPI: wfsAsyncExecute(HSERVICE, DWORD, Type, DWORD, HWND): hService=1,dwCommand=1303,lpCmdData=at.o2xfs.xfs.cim.v3_00.CashInStart3@1710f1a[tellerID=0,useRecycleUnits=false,outputPosition=OUTREAR,inputPosition=INFRONT],dwTimeOut=0,hWnd=18070800 2017-03-15 09:48:31,555 DEBUG [MessageHandler] at.o2xfs.xfs.service.cmd.XfsCallable: call(): Waiting ... what should I "waiting..." for ? and what is mean "waiting..." in this LOG ? The money already inside cassette

  3. how to get status in CASH_IN_END command ? I mean like success deposit or etc. seems like after execute wfsResultCashEnd = cashEndCommand.call();, the next line not execeute because get "waiting..." in Log

  4. How to get one of event in cimService.addCimServiceListener(new CimServiceListener() { like below

    cimService.addCimServiceListener(new CimServiceListener() {

            @Override
            public void onCimShutterStatusChanged(
                    ShutterStatusChanged3_30 shutterStatusChanged) {
                System.out.println("onCimShutterStatusChanged : "
                        + shutterStatusChanged);
            }
    
            @Override
            public void onCimSafeDoorOpen() {
                System.out.println("onCimSafeDoorOpen : ");
            }
    
            @Override
            public void onCimSafeDoorClosed() {
                System.out.println("onCimSafeDoorClosed : ");
            }
    
            @Override
            public void onCimItemsTaken(at.o2xfs.xfs.cim.Position position) {
                System.out.println("onCimItemsTaken : " + position);
            }
    
            @Override
            public void onCimItemsPresented() {
                System.out.println("onCimItemsPresented : ");
            }
    
            @Override
            public void onCimItemsInsert(at.o2xfs.xfs.cim.Position position) {
                System.out.println("onCimItemsInsert : " + position);
            }
                            ....
        });

    Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

It's not recommended to execute another command during event processing (methods in XfsEventNotification). Waiting for a result in fireOperationCompleteEvent will not work at all, because the Thread is blocked. As I mentioned in Issue #42, I would suggest do create a state machine. In fireOperationCompleteEvent you just set a boolean and notify the Thread about the state change. Check EjectCardCommand for details.

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

Thanks for your explanation. How about my number 4 question above ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

CimService must overwrite fireServiceEvent(WFSResult) and handle all SRVE_ events accordingly, take CdmService as an example.

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Thanks @AndreasFagschlunger

AndreasFagschlunger commented 7 years ago

Be sure to check out the latest commit d737af6 where I added a untested version of various CIM commands.

Shroudedd commented 6 years ago

@AndreasFagschlunger Hello, I am quite new to all of this im just looking around for now and learning python. I read about ATM malware called tyupkin, it would infect an atm machine then tell it to dispense all of the notes. I also read about a black box attack where a raspberry pi was connected via usb and a command was sent to do the same thing. Do you know how this works? Is it really as simple as creating a java script that send the correct command to the correct device?

Shroudedd commented 6 years ago

haha sounds wrong when you read it, java file* sounds better

AndreasFagschlunger commented 6 years ago

Hello @Shroudedd! For the future, you can create a issue and tag it as question, since it is off topic. But anyway, the CEN/XFS API doesn't deal with security. So if you manage to run your own executable (C, Java, etc.) on an ATM, it will dispense and present cash. But usually an ATM is hardened enough so you shouln't be able to copy your "malware" and execute it. The Raspberry PI thing targets directly to the hardware. So you plug the cash dispenser to you raspberry (or other computer) directly and try to dispense/present cash directly. This would be possible if the USB communication isn't encrypted, which it usually is. Also you need deep knowledge of the hardware you're dealing with, since every cash dispenser (and firmware) is different.

Best regards, Andreas Fagschlunger

Shroudedd commented 6 years ago

Thank you for the quick reply, it went to a separate folder for some reason and I just now saw your email. Yes I saw a video on youtube of someone showing how they unplug the dispenser and plug it into a black box and it works. The XFS documentation covers all the proper commands and format but what im confused is how exactly are the commands send? like through a terminal? Plugging the dispenser into a laptop would show it as a connected device, but through what means are the commands sent?

On Wed, Apr 11, 2018 at 1:47 AM, AndreasFagschlunger < notifications@github.com> wrote:

Hello @Shroudedd https://github.com/Shroudedd! For the future, you can create a issue and tag it as question, since it is off topic. But anyway, the CEN/XFS API doesn't deal with security. So if you manage to run your own executable (C, Java, etc.) on an ATM, it will dispense and present cash. But usually an ATM is hardened enough so you shouln't be able to copy your "malware" and execute it. The Raspberry PI thing targets directly to the hardware. So you plug the cash dispenser to you raspberry (or other computer) directly and try to dispense/present cash directly. This would be possible if the USB communication isn't encrypted, which it usually is. Also you need deep knowledge of the hardware you're dealing with, since every cash dispenser (and firmware) is different.

Best regards, Andreas Fagschlunger

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-380376425, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF-JMtmz41SSCzJlsbzshPa0phERBks5tncM3gaJpZM4MaxZs .

AndreasFagschlunger commented 6 years ago

If you say they plug it into a black box, I'm pretty sure this is the second scenario where CEN/XFS isn't involved. The just communicate directly with the dispenser (USB). If their isn't any encryption, you just need to send the right commands (or bits and bytes). That's what I meant by needing deep knowledge of the hardware. There is no standard on how the XFS Service Provider communicates with the hardware. So communicating with the hardware directly over USB is something very low level and device specific.

Shroudedd commented 6 years ago

I understand but if its plugged directly into the device, you still need to send xfs commands right? Because that's the only thing that the device accepts as a command to dispense? Are you aware of any resources online I could look at that explains this subject?

On Fri, Apr 13, 2018, 1:43 AM AndreasFagschlunger notifications@github.com wrote:

If you say they plug it into a black box, I'm pretty sure this is the second scenario where CEN/XFS isn't involved. The just communicate directly with the dispenser (USB). If their isn't any encryption, you just need to send the right commands (or bits and bytes). That's what I meant by needing deep knowledge of the hardware. There is no standard on how the XFS Service Provider communicates with the hardware. So communicating with the hardware directly over USB is something very low level and device specific.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381067719, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF5EJkPLRRwl31k1xtcJmqFi6zLLKks5toGU-gaJpZM4MaxZs .

AndreasFagschlunger commented 6 years ago

No, as I said before the protocol used to communicate with the dispenser over USB etc. is not standardized and beyond the scope of XFS. It is a proprietary protocol specific to the hardware used. As of resources, you can ask Google about jackpotting attacks. Here is what I found: https://krebsonsecurity.com/2018/01/first-jackpotting-attacks-hit-u-s-atms/

Shroudedd commented 6 years ago

Thank you for the response and taking time out of your day to explain this to me. I'm sorry I'm having difficulty understanding it still, the atm software communicate with the xfs manager which sends commands through to the device service provider which then sends the command to the device, am I right? Xfsmanager>>api/spi>>sp>>device? So by bypassing the chain and plugging directly into the device, why would I not still send the xfs command? Does the service provider translate the xfs command and send something else to the device? Also, how do you go about figuring out the correct bytes to send if you plug in directly? Do I have to find the sp.dll and look inside of that?

On Sat, Apr 14, 2018, 12:28 AM AndreasFagschlunger notifications@github.com wrote:

No, as I said before the protocol used to communicate with the dispenser over USB etc. is not standardized and beyond the scope of XFS. It is a proprietary protocol specific to the hardware used. As of resources, you can ask Google about jackpotting attacks. Here is what I found: https://krebsonsecurity.com/2018/01/first-jackpotting-attacks-hit-u-s-atms/

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381310269, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF51N_CGOSPUhjlsNenoyePkBjniKks5toaU2gaJpZM4MaxZs .

AndreasFagschlunger commented 6 years ago

First off, yes the SP sends something else to the device. See, CEN/XFS is a standardized C-API. So it is a function call with defined parameters on a defined library (msxfs.dll). A hardware doesn't has libraries, it has cables (or antennas) and communicates through them. So the whole idea behind XFS is, that you don't want to deal with this hardware specific things. You know it's a dispenser, so you want it to dispense something. You don't care if the dispenser is from NCR or Diebold-Nixdorf and how it is connected to the PC (USB, Serial-Port, whatever). You buy an ATM which supports XFS, you know there is a msxfs.dll installed, you know which functions to call to dispense cash. The rest is not your concern, the SP from NCR, Diebold-Nixdorf, etc. knows how to process your request and howto tell the dispenser to do the things you requested.

That said, the only way you can use XFS commands on your "black box" is, that your black box has a suitable XFS SP installed.

And if you don't have documents about how something works, you have to use reverse engineering. For example, you can trace the USB connection and see which bytes are send in which situation etc. But I'm not an hacker, so I don't know how such things are usually done.

Shroudedd commented 6 years ago

Okay that cleared it up for me thank you. So if it was a black box attack the attacker would have to know the specific device specs, alot harder of a challenge than just installing malware that uses the xfs right? Thanks man!

On Sat, Apr 14, 2018 at 3:23 PM, AndreasFagschlunger < notifications@github.com> wrote:

First off, yes the SP sends something else to the device. See, CEN/XFS is a standardized C-API. So it is a function call with defined parameters on a defined library (msxfs.dll). A hardware doesn't has libraries, it has cables (or antennas) and communicates through them. So the whole idea behind XFS is, that you don't want to deal with this hardware specific things. You know it's a dispenser, so you want it to dispense something. You don't care if the dispenser is from NCR or Diebold-Nixdorf and how it is connected to the PC (USB, Serial-Port, whatever). You buy an ATM which supports XFS, you know there is a msxfs.dll installed, you know which functions to call to dispense cash. The rest is not your concern, the SP from NCR, Diebold-Nixdorf, etc. knows how to process your request and howto tell the dispenser to do the things you requested.

That said, the only way you can use XFS commands on your "black box" is, that your black box has a suitable XFS SP installed.

And if you don't have documents about how something works, you have to use reverse engineering. For example, you can trace the USB connection and see which bytes are send in which situation etc. But I'm not an hacker, so I don't know how such things are usually done.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381364835, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF1aH7yibqk_hiMby6i5f9Btf31Fdks5tonbEgaJpZM4MaxZs .

Shroudedd commented 6 years ago

Im pretty familiar with python but I dont think something like this could be accomplished with python, can it? So i am in the process of learning c++ right now. Also, what is the XFS sdk for?

On Sat, Apr 14, 2018 at 9:48 PM, Yury Rashnikov yury.rashnikov@gmail.com wrote:

Okay that cleared it up for me thank you. So if it was a black box attack the attacker would have to know the specific device specs, alot harder of a challenge than just installing malware that uses the xfs right? Thanks man!

On Sat, Apr 14, 2018 at 3:23 PM, AndreasFagschlunger < notifications@github.com> wrote:

First off, yes the SP sends something else to the device. See, CEN/XFS is a standardized C-API. So it is a function call with defined parameters on a defined library (msxfs.dll). A hardware doesn't has libraries, it has cables (or antennas) and communicates through them. So the whole idea behind XFS is, that you don't want to deal with this hardware specific things. You know it's a dispenser, so you want it to dispense something. You don't care if the dispenser is from NCR or Diebold-Nixdorf and how it is connected to the PC (USB, Serial-Port, whatever). You buy an ATM which supports XFS, you know there is a msxfs.dll installed, you know which functions to call to dispense cash. The rest is not your concern, the SP from NCR, Diebold-Nixdorf, etc. knows how to process your request and howto tell the dispenser to do the things you requested.

That said, the only way you can use XFS commands on your "black box" is, that your black box has a suitable XFS SP installed.

And if you don't have documents about how something works, you have to use reverse engineering. For example, you can trace the USB connection and see which bytes are send in which situation etc. But I'm not an hacker, so I don't know how such things are usually done.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381364835, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF1aH7yibqk_hiMby6i5f9Btf31Fdks5tonbEgaJpZM4MaxZs .

Shroudedd commented 6 years ago

I just installed the XFS sdk on my computer, thinking it was an actual SDK to develop your own xfs compliant applications, but as far as i can tell, all it installed was the dll is that right? Sorry for blowing you up with all these questions. I spend hours researching this stuff and its just nice having found someone who is knowledgeable on this topic lol.

On Sat, Apr 14, 2018 at 9:52 PM, Yury Rashnikov yury.rashnikov@gmail.com wrote:

Im pretty familiar with python but I dont think something like this could be accomplished with python, can it? So i am in the process of learning c++ right now. Also, what is the XFS sdk for?

On Sat, Apr 14, 2018 at 9:48 PM, Yury Rashnikov yury.rashnikov@gmail.com wrote:

Okay that cleared it up for me thank you. So if it was a black box attack the attacker would have to know the specific device specs, alot harder of a challenge than just installing malware that uses the xfs right? Thanks man!

On Sat, Apr 14, 2018 at 3:23 PM, AndreasFagschlunger < notifications@github.com> wrote:

First off, yes the SP sends something else to the device. See, CEN/XFS is a standardized C-API. So it is a function call with defined parameters on a defined library (msxfs.dll). A hardware doesn't has libraries, it has cables (or antennas) and communicates through them. So the whole idea behind XFS is, that you don't want to deal with this hardware specific things. You know it's a dispenser, so you want it to dispense something. You don't care if the dispenser is from NCR or Diebold-Nixdorf and how it is connected to the PC (USB, Serial-Port, whatever). You buy an ATM which supports XFS, you know there is a msxfs.dll installed, you know which functions to call to dispense cash. The rest is not your concern, the SP from NCR, Diebold-Nixdorf, etc. knows how to process your request and howto tell the dispenser to do the things you requested.

That said, the only way you can use XFS commands on your "black box" is, that your black box has a suitable XFS SP installed.

And if you don't have documents about how something works, you have to use reverse engineering. For example, you can trace the USB connection and see which bytes are send in which situation etc. But I'm not an hacker, so I don't know how such things are usually done.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381364835, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF1aH7yibqk_hiMby6i5f9Btf31Fdks5tonbEgaJpZM4MaxZs .

AndreasFagschlunger commented 6 years ago

There are ways to access DLLs in Python, just Google for it, e.g. https://stackoverflow.com/questions/252417/how-can-i-use-a-dll-file-from-python The default location for XFS SDK is C:/Program Files (x86)/Common Files/XFS/SDK. You can take a look at xfs-sdk.ps1, it downloads all SDKs and unpacks them. The msxfs.dll which gets installed is the default implementation for the XFS Manager.

Shroudedd commented 6 years ago

Thank you, I'm going to try and do it with c++ though, will be a good learning experience. How I understand it std::cout uses the standard namespace and cout is the output function, so xfs would it be xfs::xfscommand?

On Sun, Apr 15, 2018, 2:17 AM AndreasFagschlunger notifications@github.com wrote:

There are ways to access DLLs in Python, just Google for it, e.g. https://stackoverflow.com/questions/252417/how-can-i-use-a-dll-file-from-python The default location for XFS SDK is C:/Program Files (x86)/Common Files/XFS/SDK. You can take a look at xfs-sdk.ps1 https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/xfs-sdk.ps1, it downloads all SDKs and unpacks them. The msxfs.dll which gets installed is the default implementation for the XFS Manager.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381392056, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaFxVX8lK2zAueYEE-LIpbfYrEOzaPks5toxAegaJpZM4MaxZs .

Shroudedd commented 6 years ago

Something along those lines?

On Sun, Apr 15, 2018, 1:02 PM Yury Rashnikov yury.rashnikov@gmail.com wrote:

Thank you, I'm going to try and do it with c++ though, will be a good learning experience. How I understand it std::cout uses the standard namespace and cout is the output function, so xfs would it be xfs::xfscommand?

On Sun, Apr 15, 2018, 2:17 AM AndreasFagschlunger < notifications@github.com> wrote:

There are ways to access DLLs in Python, just Google for it, e.g. https://stackoverflow.com/questions/252417/how-can-i-use-a-dll-file-from-python The default location for XFS SDK is C:/Program Files (x86)/Common Files/XFS/SDK. You can take a look at xfs-sdk.ps1 https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/xfs-sdk.ps1, it downloads all SDKs and unpacks them. The msxfs.dll which gets installed is the default implementation for the XFS Manager.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381392056, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaFxVX8lK2zAueYEE-LIpbfYrEOzaPks5toxAegaJpZM4MaxZs .

Shroudedd commented 6 years ago

Do you have any sample code that shows using and sending an xfs command to any device that I can just look at and study instead of bothering you?

On Sun, Apr 15, 2018, 1:03 PM Yury Rashnikov yury.rashnikov@gmail.com wrote:

Something along those lines?

On Sun, Apr 15, 2018, 1:02 PM Yury Rashnikov yury.rashnikov@gmail.com wrote:

Thank you, I'm going to try and do it with c++ though, will be a good learning experience. How I understand it std::cout uses the standard namespace and cout is the output function, so xfs would it be xfs::xfscommand?

On Sun, Apr 15, 2018, 2:17 AM AndreasFagschlunger < notifications@github.com> wrote:

There are ways to access DLLs in Python, just Google for it, e.g. https://stackoverflow.com/questions/252417/how-can-i-use-a-dll-file-from-python The default location for XFS SDK is C:/Program Files (x86)/Common Files/XFS/SDK. You can take a look at xfs-sdk.ps1 https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/xfs-sdk.ps1, it downloads all SDKs and unpacks them. The msxfs.dll which gets installed is the default implementation for the XFS Manager.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381392056, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaFxVX8lK2zAueYEE-LIpbfYrEOzaPks5toxAegaJpZM4MaxZs .

Shroudedd commented 6 years ago

I used your script to install all the sdk, I found the header files that i need to use int he c program. I think thats what I was looking for. Now just to figure out the syntax

On Sun, Apr 15, 2018 at 1:06 PM, Yury Rashnikov yury.rashnikov@gmail.com wrote:

Do you have any sample code that shows using and sending an xfs command to any device that I can just look at and study instead of bothering you?

On Sun, Apr 15, 2018, 1:03 PM Yury Rashnikov yury.rashnikov@gmail.com wrote:

Something along those lines?

On Sun, Apr 15, 2018, 1:02 PM Yury Rashnikov yury.rashnikov@gmail.com wrote:

Thank you, I'm going to try and do it with c++ though, will be a good learning experience. How I understand it std::cout uses the standard namespace and cout is the output function, so xfs would it be xfs::xfscommand?

On Sun, Apr 15, 2018, 2:17 AM AndreasFagschlunger < notifications@github.com> wrote:

There are ways to access DLLs in Python, just Google for it, e.g. https://stackoverflow.com/questions/252417/how-can-i- use-a-dll-file-from-python The default location for XFS SDK is C:/Program Files (x86)/Common Files/XFS/SDK. You can take a look at xfs-sdk.ps1 https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/xfs-sdk.ps1, it downloads all SDKs and unpacks them. The msxfs.dll which gets installed is the default implementation for the XFS Manager.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381392056, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaFxVX8lK2zAueYEE-LIpbfYrEOzaPks5toxAegaJpZM4MaxZs .

AndreasFagschlunger commented 6 years ago

Why not using O²Xfs? Java is easy to understand and examples are already there. But either way, you can take a look at the C++ sources for at.o2xfs.xfs.dll: https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/at.o2xfs.xfs/src/at.o2xfs.xfs.dll/cpp/at.o2xfs.xfs.cpp https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/at.o2xfs.xfs/src/at.o2xfs.xfs.dll/cpp/MessageHandler.cpp

Just ignore the Java/JNI parts and focus on the parts using XFS-API. The DLL must create a message window, load the msxfs.dll, etc. otherwise you maybe take a look at this code:

https://github.com/sebastianscatularo/freexfs/tree/master/Samples/WosaXFSTest20100106

And read the CEN/XFS API documentation, at least Part 1:

https://www.cen.eu/work/areas/ICT/eBusiness/Pages/CWA16926.aspx

Shroudedd commented 6 years ago

Okay cool thanks. Reason I want to do it with c++ is it's a harder language and I want to learn hard ones first then the rest

On Sun, Apr 15, 2018, 2:37 PM AndreasFagschlunger notifications@github.com wrote:

Why not using O²Xfs? Java is easy to understand and examples are already there. But either way, you can take a look at the C++ sources for at.o2xfs.xfs.dll:

https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/at.o2xfs.xfs/src/at.o2xfs.xfs.dll/cpp/at.o2xfs.xfs.cpp

https://github.com/AndreasFagschlunger/O2Xfs/blob/develop/at.o2xfs.xfs/src/at.o2xfs.xfs.dll/cpp/MessageHandler.cpp

Just ignore the Java/JNI parts and focus on the parts using XFS-API. The DLL must create a message window, load the msxfs.dll, etc. otherwise you maybe take a look at this code:

https://github.com/sebastianscatularo/freexfs/tree/master/Samples/WosaXFSTest20100106

And read the CEN/XFS API documentation, at least Part 1:

https://www.cen.eu/work/areas/ICT/eBusiness/Pages/CWA16926.aspx

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381440067, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF0zCwKdQRaoJqSEWgGKy_fKx1z3Oks5to722gaJpZM4MaxZs .

Shroudedd commented 6 years ago

Hey Andreas, another quick question; I think the blackbox method connecting directly to the dispenser is the harder one because of the encryption like you said and because I would need specific sp information correct? Take a look at this https://youtu.be/Uxd0TRdE6sw What are they plugging into? Its an ethernet port but is it just like the ethernet port on the back of my tower?

On Sun, Apr 15, 2018 at 5:56 PM, Yury Rashnikov yury.rashnikov@gmail.com wrote:

Okay cool thanks. Reason I want to do it with c++ is it's a harder language and I want to learn hard ones first then the rest

On Sun, Apr 15, 2018, 2:37 PM AndreasFagschlunger < notifications@github.com> wrote:

Why not using O²Xfs? Java is easy to understand and examples are already there. But either way, you can take a look at the C++ sources for at.o2xfs.xfs.dll: https://github.com/AndreasFagschlunger/O2Xfs/ blob/develop/at.o2xfs.xfs/src/at.o2xfs.xfs.dll/cpp/at.o2xfs.xfs.cpp https://github.com/AndreasFagschlunger/O2Xfs/ blob/develop/at.o2xfs.xfs/src/at.o2xfs.xfs.dll/cpp/MessageHandler.cpp

Just ignore the Java/JNI parts and focus on the parts using XFS-API. The DLL must create a message window, load the msxfs.dll, etc. otherwise you maybe take a look at this code:

https://github.com/sebastianscatularo/freexfs/tree/master/Samples/ WosaXFSTest20100106

And read the CEN/XFS API documentation, at least Part 1:

https://www.cen.eu/work/areas/ICT/eBusiness/Pages/CWA16926.aspx

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-381440067, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF0zCwKdQRaoJqSEWgGKy_fKx1z3Oks5to722gaJpZM4MaxZs .

AndreasFagschlunger commented 6 years ago

This is obviously scenario one. As I said, CEN/XFS doesn't cover security aspects. So if you manage to start your own executable on an ATM where XFS is installed, it willingly dispenses all the money you ask for - it doesn't even need administrator privileges.

You literally see that they using some kind of exploit to get access to the operating system and then copy and start their ATM_XFS.exe.

Shroudedd commented 6 years ago

I get what they're doing I just didn't get how they were transferring the file over through ethernet. After further digging it looks like they connected the raspberry pi to the local network and then ssh'd to it and through and unpatched xp exploit opened a reverse shell. Now the part I can't figure out is how would then find the ethernet ip address of the atm..

On Tue, Apr 17, 2018, 11:20 PM AndreasFagschlunger notifications@github.com wrote:

This is obviously scenario one. As I said, CEN/XFS doesn't cover security aspects. So if you manage to start your own executable on an ATM where XFS is installed, it willingly dispenses all the money you ask for - it doesn't even need administrator privileges.

You literally see that they using some kind of exploit to get access to the operating system and then copy and start their ATM_XFS.exe.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AndreasFagschlunger/O2Xfs/issues/43#issuecomment-382275632, or mute the thread https://github.com/notifications/unsubscribe-auth/AjaaF1R_svyEMvKL5PuVrphrXOZFeUM0ks5tpttCgaJpZM4MaxZs .