📜 ⬆️ ⬇️

Network scan on Xerox 3220 with VPN connected

The essence of the problem


The Xerox 3220 MFP supports network scanning through a Network Scan application installed on one of the computers on the network in which this MFP is registered by IP address. But once the production need required to use VPN connections on this computer (Cisco VPN Client and OpenVPN). And at the moment of connecting any of the connections, the connection with the scanner from the application was instantly lost. My research process and solution of this problem will continue.

First look


Immediately, the thought about the default gateways being replaced, the potential wrapping of all traffic in the VPN, is rejected as inoperative, since All this is not in any of the connections used. The web-interface of the scanner is still available, in the end, it is corny. Then to me, as a network engineer in the first place, it became interesting how the scanner is detected on the network.
For this, I used Wireshark, running it without a VPN connection on the local network interface. Found that the application sends a broadcast udp packet to port 1124, to which the scanner responds. Now we connect VPN and there is complete silence on the local interface, no outgoing packets.

And what's inside?


Well, it is obvious that for some reason the program starts sending packets to the wrong interface, and there, of course, no one responds to it. How to fix it, I was completely incomprehensible, because if the application were guided by the routing table along with the address of the scanner, or something else sane, then everything should have been fine, but this was not the case. So, you need to at least understand the interface selection algorithm, and I decided to implement it using OllyDbg.
Having launched NSCSysUI_XEROX.exe under the debugger (the network scanning application itself, which included a number of * .dll), I, as expected, did not understand anything, because although this is not my first reverse engineering experience, but the previous ones were not particularly successful.

Detection of the scanner clearly occurred, including after pressing the “Refresh” button, and I noticed that in OllyDbg at this moment some kind of debug string output occurs. The last message was just about how the selected IP address of the interface:

For this line of "Selected IP NIC" I decided to catch on. I tried to search for it immediately through Search For - All referenced strings, but there it did not turn out, which made me somewhat depressed and a long F7 from the entry point into the .exe file. As a result, it turned out that it was not at all surprising that there was no line where I was looking for it, since This debug output belongs to a call from NSCProtocol_XEROX.dll, in which that line is already successfully located, and, hooray, this is the procedure with a message:
003B737D |. FF75 DC PUSH DWORD PTR SS:[EBP-24] ; /<%s> 003B7380 |. 8D45 F0 LEA EAX,[EBP-10] ; | 003B7383 |. C645 FC 12 MOV BYTE PTR SS:[EBP-4],12 ; | 003B7387 |. 68 04A13D00 PUSH OFFSET 003DA104 ; |Format = "Selected NIC IP : %s" 003B738C |. 50 PUSH EAX ; |Arg1 003B738D |. E8 D6F70000 CALL 003C6B68 ; \NSCProtocol_XEROX.003C6B68 

But this is still not interesting, we are looking for what is there at all in this procedure. First of all, the eye caught on it in calling the function gethostbyname (), which, as MSDN tells us, also returns the entire list of IP addresses by the specified symbolic name.

 003B6FCA |. 50 PUSH EAX ; /Arg1,  EAX   003B6FCB |. E8 1EF70000 CALL <JMP.&WSOCK32.#52> ; \WS2_32.gethostbyname 003B6FD0 |. 8BF8 MOV EDI,EAX ;   EDI   hostbyname ( EAX) 003B6FD2 |. 3BFE CMP EDI,ESI ;      hostbyname 003B6FD4 |.- 74 34 JE SHORT 003B700A 003B6FD6 |. 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] ;     IP    003B6FD9 |. 8B00 MOV EAX,DWORD PTR DS:[EAX] ;   IP  003B6FDB |. FF30 PUSH DWORD PTR DS:[EAX] ; /Arg1 003B6FDD |. E8 06F70000 CALL <JMP.&WSOCK32.#11> ; \WS2_32.inet_ntoa 003B6FE2 |. 50 PUSH EAX ; /Arg1, -      003B6FE3 |. 8D4D D4 LEA ECX,[EBP-2C] ; | 003B6FE6 |. E8 FD050100 CALL 003C75E8 ; \NSCProtocol_XEROX.003C75E8 003B6FEB |. 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] ;      IP 003B6FEE |. 8B00 MOV EAX,DWORD PTR DS:[EAX] ;     IP 003B6FF0 |. 3BC6 CMP EAX,ESI 003B6FF2 |.- 74 16 JE SHORT 003B700A 003B6FF4 |. 33DB XOR EBX,EBX ;  EBX      IP  003B6FF6 |> FF30 /PUSH DWORD PTR DS:[EAX] ; /Arg1,   IP     003B6FF8 |. E8 EBF60000 |CALL <JMP.&WSOCK32.#11> ; \WS2_32.inet_ntoa 003B6FFD |. 8B47 0C |MOV EAX,DWORD PTR DS:[EDI+0C] 003B7000 |. 83C3 04 |ADD EBX,4 003B7003 |. 8B0418 |MOV EAX,DWORD PTR DS:[EBX+EAX] 003B7006 |. 3BC6 |CMP EAX,ESI 003B7008 |.- 75 EC \JNE SHORT 003B6FF6 ;    !         003B700A |> E8 D3F60000 CALL <JMP.&WSOCK32.#116> ; [WS2_32.WSACleanup,        IP ,  -      

Comments speak for themselves. Seeing such a strange application logic, I thought that here it is the key - the program simply uses the first of the array of IP addresses, and for the rest it just runs for nothing. This confidence was supported by the test call gethostbyname (), in the returned structure of which, in the array of addresses, the IP address of the VPN connection always appeared in the first place. And here I had two solutions. The first is to write a bootloader that would intercept gethostbyname () for the specified process and return, or put in the first place the desired IP address. But since I once did this, it was not sporty, and I decided to try the second - patch dll at least at a primitive level.
I replaced the entire specified piece of code with something that in my opinion more corresponded to my case (although I must admit, it is no different from the approach of the application) and drove the only call (assuming that it is some extremely useful) that participates in the above code Only at the first IP address, but for all those encountered:
 003B6FD6 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] ;     IP    003B6FD9 8B00 MOV EAX,DWORD PTR DS:[EAX] ;   IP  003B6FDB 33DB XOR EBX,EBX 003B6FDD FF30 PUSH DWORD PTR DS:[EAX] 003B6FDF E8 04F70000 CALL <JMP.&WSOCK32.#11> ; Jump to WS2_32.inet_ntoa 003B6FE4 50 PUSH EAX 003B6FE5 8D4D D4 LEA ECX,[EBP-2C] 003B6FE8 E8 FB050100 CALL 003C75E8 003B6FED 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] 003B6FF0 83C3 04 ADD EBX,4 003B6FF3 8B0418 MOV EAX,DWORD PTR DS:[EBX+EAX] 003B6FF6 3BC6 CMP EAX,ESI ;   IP     003B6FF8 ^ 75 E3 JNE SHORT 003B6FDD 003B6FFA 90 NOP ... 003B7009 90 NOP 003B700A |> E8 D3F60000 CALL <JMP.&WSOCK32.#116> 

What, according to my assumptions, was to force the application to choose not the first IP address, but the last one. Well, or all at once.
However, in the behavior of the application it did not change anything at all. This outcome was also hinted that the output of that debug line used a memory area in which writing had not even occurred. Well, look further.
')

Moment of truth


Then I went down a little lower in the listing, and I saw a call to GetAdaptersInfo (), followed by a loop on quite a few lines, which seemed to be trying to go through each record from the list returned by the function. I meditated on this code for 2 days. And I still haven’t completely understood the logic, but my version is this: the first record is taken, it is checked for the type of interface, non-zero IP address, and the length of the character representation (? This is the most mysterious test for me) of the gateway default for this interface. If the type is appropriate, the address is and the symbolic representation of the gateway is not zero, then we exit the loop and, it turns out, this adapter is selected. And here is the nuance. For my VPN connection, there is no default gateway at all, but the C ++ test call GetAdaptersInfo () with MSDN code does not return it as a missing value, but as “0.0.0.0”, respectively, the length is not zero, and this interface in all respects fits And since He is the first in the list, then he is selected.
Here I was completely sad, and I did not understand how to fix this code for correct operation. But you just need to carefully read the documentation. The function description says:
The GetAdaptersInfo function can retrieve information only for IPv4 addresses.
It can be controlled from the network folder.

If you, like me (and I come across windows administration starting from win2000 server), have never seen this menu before, then this is where it is in Win7:


Where, of course, I saw that all my VPN adapters are above the local network connection, moving it to the very top, I solved the original problem.

PS But still, developers from Xerox could send test requests to all interfaces, and not just to the first available one.

Source: https://habr.com/ru/post/219461/


All Articles