Advertisement
Guest User

Untitled

a guest
Sep 27th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.69 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import socket
  5. import struct
  6. import time
  7. from hashlib import md5
  8. import sys
  9. import os
  10. import random
  11. import traceback
  12.  
  13. # CONFIG
  14. server = "192.168.100.150"
  15. username = ""
  16. password = ""
  17. host_name = "LIYUANYUAN"
  18. host_os = "DrCOM"
  19. host_ip = "10.30.22.17"
  20. PRIMARY_DNS = "114.114.114.114"
  21. dhcp_server = "0.0.0.0"
  22. mac = 0xb888e3051680
  23. CONTROLCHECKSTATUS = '\x20'
  24. ADAPTERNUM = '\x01'
  25. KEEP_ALIVE_VERSION = '\xdc\x02'
  26. '''
  27. AUTH_VERSION:
  28. unsigned char ClientVerInfoAndInternetMode;
  29. unsigned char DogVersion;
  30. '''
  31. AUTH_VERSION = '\x0a\x00'
  32. IPDOG = '\x01'
  33. ror_version = False
  34. # CONFIG_END
  35.  
  36. nic_name = '' #Indicate your nic, e.g. 'eth0.2'.nic_name
  37. bind_ip = '0.0.0.0'
  38.  
  39. class ChallengeException (Exception):
  40. def __init__(self):
  41. pass
  42.  
  43. class LoginException (Exception):
  44. def __init__(self):
  45. pass
  46.  
  47. def bind_nic():
  48. try:
  49. import fcntl
  50. def get_ip_address(ifname):
  51. s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  52. return socket.inet_ntoa(fcntl.ioctl(
  53. s.fileno(),
  54. 0x8915, # SIOCGIFADDR
  55. struct.pack('256s', ifname[:15])
  56. )[20:24])
  57. return get_ip_address(nic_name)
  58. except ImportError as e:
  59. print('Indicate nic feature need to be run under Unix based system.')
  60. return '0.0.0.0'
  61. except IOError as e:
  62. print(nic_name + 'is unacceptable !')
  63. return '0.0.0.0'
  64. finally:
  65. return '0.0.0.0'
  66.  
  67. if nic_name != '':
  68. bind_ip = bind_nic()
  69.  
  70. s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  71. # s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  72. s.bind((bind_ip, 61440))
  73.  
  74. s.settimeout(3)
  75. SALT = ''
  76. IS_TEST = True
  77. # specified fields based on version
  78. CONF = "/etc/drcom.conf"
  79. UNLIMITED_RETRY = True
  80. EXCEPTION = False
  81. DEBUG = False #log saves to file
  82. LOG_PATH = '/var/log/drcom_client.log'
  83. if IS_TEST:
  84. DEBUG = True
  85. LOG_PATH = 'drcom_client.log'
  86.  
  87.  
  88. def log(*args, **kwargs):
  89. s = ' '.join(args)
  90. print s
  91. if DEBUG:
  92. with open(LOG_PATH,'a') as f:
  93. f.write(s + '\n')
  94.  
  95. def challenge(svr,ran):
  96. while True:
  97. t = struct.pack("<H", int(ran)%(0xFFFF))
  98. s.sendto("\x01\x04"+t+"\x2d"+"\x00"*15, (svr, 61440))
  99. try:
  100. data, address = s.recvfrom(1024)
  101. log('[challenge] recv',data.encode('hex'))
  102. except:
  103. log('[challenge] timeout, retrying...')
  104. continue
  105.  
  106. if address == (svr, 61440):
  107. break
  108. else:
  109. continue
  110. log('[DEBUG] challenge:\n' + data.encode('hex'))
  111. if data[0] != '\x02':
  112. raise ChallengeException
  113. log('[challenge] challenge packet sent.')
  114. return data[4:8]
  115.  
  116. def md5sum(s):
  117. m = md5()
  118. m.update(s)
  119. return m.digest()
  120.  
  121. def dump(n):
  122. s = '%x' % n
  123. if len(s) & 1:
  124. s = '0' + s
  125. return s.decode('hex')
  126.  
  127. def ror(md5, pwd):
  128. ret = ''
  129. for i in range(len(pwd)):
  130. x = ord(md5[i]) ^ ord(pwd[i])
  131. ret += chr(((x<<3)&0xFF) + (x>>5))
  132. return ret
  133.  
  134. def keep_alive_package_builder(number,random,tail,type=1,first=False):
  135. data = '\x07'+ chr(number) + '\x28\x00\x0b' + chr(type)
  136. if first :
  137. data += '\x0f\x27'
  138. else:
  139. data += KEEP_ALIVE_VERSION
  140. data += '\x3c\x69' + '\x00' * 6
  141. data += tail
  142. data += '\x00' * 4
  143. #data += struct.pack("!H",0xdc02)
  144. if type == 3:
  145. foo = ''.join([chr(int(i)) for i in host_ip.split('.')]) # host_ip
  146. #CRC
  147. # edited on 2014/5/12, filled zeros to checksum
  148. # crc = packet_CRC(data+foo)
  149. crc = '\x00' * 4
  150. #data += struct.pack("!I",crc) + foo + '\x00' * 8
  151. data += crc + foo + '\x00' * 8
  152. else: #packet type = 1
  153. data += '\x00' * 16
  154. return data
  155.  
  156. # def packet_CRC(s):
  157. # ret = 0
  158. # for i in re.findall('..', s):
  159. # ret ^= struct.unpack('>h', i)[0]
  160. # ret &= 0xFFFF
  161. # ret = ret * 0x2c7
  162. # return ret
  163.  
  164. def keep_alive2(*args):
  165. #first keep_alive:
  166. #number = number (mod 7)
  167. #status = 1: first packet user sended
  168. # 2: first packet user recieved
  169. # 3: 2nd packet user sended
  170. # 4: 2nd packet user recieved
  171. # Codes for test
  172. tail = ''
  173. packet = ''
  174. svr = server
  175. ran = random.randint(0,0xFFFF)
  176. ran += random.randint(1,10)
  177. # 2014/10/15 add by latyas, maybe svr sends back a file packet
  178. svr_num = 0
  179. packet = keep_alive_package_builder(svr_num,dump(ran),'\x00'*4,1,True)
  180. while True:
  181. log('[keep-alive2] send1',packet.encode('hex'))
  182. s.sendto(packet, (svr, 61440))
  183. data, address = s.recvfrom(1024)
  184. log('[keep-alive2] recv1',data.encode('hex'))
  185. if data.startswith('\x07\x00\x28\x00') or data.startswith('\x07' + chr(svr_num) + '\x28\x00'):
  186. break
  187. elif data[0] == '\x07' and data[2] == '\x10':
  188. log('[keep-alive2] recv file, resending..')
  189. svr_num = svr_num + 1
  190. # packet = keep_alive_package_builder(svr_num,dump(ran),'\x00'*4,1, False)
  191. break
  192. else:
  193. log('[keep-alive2] recv1/unexpected',data.encode('hex'))
  194. #log('[keep-alive2] recv1',data.encode('hex'))
  195.  
  196. ran += random.randint(1,10)
  197. packet = keep_alive_package_builder(svr_num, dump(ran),'\x00'*4,1,False)
  198. log('[keep-alive2] send2',packet.encode('hex'))
  199. s.sendto(packet, (svr, 61440))
  200. while True:
  201. data, address = s.recvfrom(1024)
  202. if data[0] == '\x07':
  203. svr_num = svr_num + 1
  204. break
  205. else:
  206. log('[keep-alive2] recv2/unexpected',data.encode('hex'))
  207. log('[keep-alive2] recv2',data.encode('hex'))
  208. tail = data[16:20]
  209.  
  210.  
  211. ran += random.randint(1,10)
  212. packet = keep_alive_package_builder(svr_num,dump(ran),tail,3,False)
  213. log('[keep-alive2] send3',packet.encode('hex'))
  214. s.sendto(packet, (svr, 61440))
  215. while True:
  216. data, address = s.recvfrom(1024)
  217. if data[0] == '\x07':
  218. svr_num = svr_num + 1
  219. break
  220. else:
  221. log('[keep-alive2] recv3/unexpected',data.encode('hex'))
  222. log('[keep-alive2] recv3',data.encode('hex'))
  223. tail = data[16:20]
  224. log("[keep-alive2] keep-alive2 loop was in daemon.")
  225.  
  226. i = svr_num
  227. while True:
  228. try:
  229. time.sleep(20)
  230. keep_alive1(*args)
  231. ran += random.randint(1,10)
  232. packet = keep_alive_package_builder(i,dump(ran),tail,1,False)
  233. #log('DEBUG: keep_alive2,packet 4\n',packet.encode('hex'))
  234. log('[keep_alive2] send',str(i),packet.encode('hex'))
  235. s.sendto(packet, (svr, 61440))
  236. data, address = s.recvfrom(1024)
  237. log('[keep_alive2] recv',data.encode('hex'))
  238. tail = data[16:20]
  239. #log('DEBUG: keep_alive2,packet 4 return\n',data.encode('hex'))
  240.  
  241. ran += random.randint(1,10)
  242. packet = keep_alive_package_builder(i+1,dump(ran),tail,3,False)
  243. #log('DEBUG: keep_alive2,packet 5\n',packet.encode('hex'))
  244. s.sendto(packet, (svr, 61440))
  245. log('[keep_alive2] send',str(i+1),packet.encode('hex'))
  246. data, address = s.recvfrom(1024)
  247. log('[keep_alive2] recv',data.encode('hex'))
  248. tail = data[16:20]
  249. #log('DEBUG: keep_alive2,packet 5 return\n',data.encode('hex'))
  250. i = (i+2) % 0xFF
  251. except:
  252. log('[keep_alive2] error', 'raise Exception to main()')
  253. raise
  254.  
  255. def checksum(s):
  256. ret = 1234
  257. x = 0
  258. for i in [x*4 for x in range(0, -(-len(s)//4))]:
  259. ret ^= int(s[i:i+4].ljust(4, '\x00')[::-1].encode('hex'), 16)
  260. ret = (1968 * ret) & 0xffffffff
  261. return struct.pack('<I', ret)
  262.  
  263. def mkpkt(salt, usr, pwd, mac):
  264. '''
  265. struct _tagLoginPacket
  266. {
  267. struct _tagDrCOMHeader Header;
  268. unsigned char PasswordMd5[MD5_LEN];
  269. char Account[ACCOUNT_MAX_LEN];
  270. unsigned char ControlCheckStatus;
  271. unsigned char AdapterNum;
  272. unsigned char MacAddrXORPasswordMD5[MAC_LEN];
  273. unsigned char PasswordMd5_2[MD5_LEN];
  274. unsigned char HostIpNum;
  275. unsigned int HostIPList[HOST_MAX_IP_NUM];
  276. unsigned char HalfMD5[8];
  277. unsigned char DogFlag;
  278. unsigned int unkown2;
  279. struct _tagHostInfo HostInfo;
  280. unsigned char ClientVerInfoAndInternetMode;
  281. unsigned char DogVersion;
  282. };
  283. '''
  284. data = '\x03\x01\x00' + chr(len(usr) + 20)
  285. data += md5sum('\x03\x01' + salt + pwd)
  286. data += usr.ljust(36, '\x00')
  287. data += CONTROLCHECKSTATUS
  288. data += ADAPTERNUM
  289. data += dump(int(data[4:10].encode('hex'),16)^mac).rjust(6, '\x00') #mac xor md51
  290. data += md5sum("\x01" + pwd + salt + '\x00' * 4) #md52
  291. data += '\x01' # number of ip
  292. data += ''.join([chr(int(i)) for i in host_ip.split('.')]) #x.x.x.x ->
  293. data += '\00' * 4 #your ipaddress 2
  294. data += '\00' * 4 #your ipaddress 3
  295. data += '\00' * 4 #your ipaddress 4
  296. data += md5sum(data + '\x14\x00\x07\x0B')[:8] #md53
  297. data += IPDOG
  298. data += '\x00'*4 # unknown2
  299. '''
  300. struct _tagOSVERSIONINFO
  301. {
  302. unsigned int OSVersionInfoSize;
  303. unsigned int MajorVersion;
  304. unsigned int MinorVersion;
  305. unsigned int BuildNumber;
  306. unsigned int PlatformID;
  307. char ServicePack[128];
  308. };
  309. struct _tagHostInfo
  310. {
  311. char HostName[HOST_NAME_MAX_LEN];
  312. unsigned int DNSIP1;
  313. unsigned int DHCPServerIP;
  314. unsigned int DNSIP2;
  315. unsigned int WINSIP1;
  316. unsigned int WINSIP2;
  317. struct _tagDrCOM_OSVERSIONINFO OSVersion;
  318. };
  319. '''
  320. data += host_name.ljust(32, '\x00') # _tagHostInfo.HostName
  321. data += ''.join([chr(int(i)) for i in PRIMARY_DNS.split('.')]) # _tagHostInfo.DNSIP1
  322. data += ''.join([chr(int(i)) for i in dhcp_server.split('.')]) # _tagHostInfo.DHCPServerIP
  323. data += '\x00\x00\x00\x00' # _tagHostInfo.DNSIP2
  324. data += '\x00' * 4 # _tagHostInfo.WINSIP1
  325. data += '\x00' * 4 # _tagHostInfo.WINSIP2
  326. data += '\x94\x00\x00\x00' # _tagHostInfo.OSVersion.OSVersionInfoSize
  327. data += '\x05\x00\x00\x00' # _tagHostInfo.OSVersion.MajorVersion
  328. data += '\x01\x00\x00\x00' # _tagHostInfo.OSVersion.MinorVersion
  329. data += '\x28\x0A\x00\x00' # _tagHostInfo.OSVersion.BuildNumber
  330. data += '\x02\x00\x00\x00' # _tagHostInfo.OSVersion.PlatformID
  331. # _tagHostInfo.OSVersion.ServicePack
  332. #data += host_os.ljust(32, '\x00')
  333. data += '\x44\x72\x43\x4f\x4d\x00\x83\x00'
  334. #data += '\x00' * 96
  335. # END OF _tagHostInfo
  336.  
  337. data += AUTH_VERSION
  338. if ror_version:
  339. '''
  340. struct _tagLDAPAuth
  341. {
  342. unsigned char Code;
  343. unsigned char PasswordLen;
  344. unsigned char Password[MD5_LEN];
  345. };
  346. '''
  347. data += '\x00' # _tagLDAPAuth.Code
  348. data += chr(len(pwd)) # _tagLDAPAuth.PasswordLen
  349. data += ror(md5sum('\x03\x01' + salt + pwd), pwd) # _tagLDAPAuth.Password
  350. '''
  351. struct _tagDrcomAuthExtData
  352. {
  353. unsigned char Code;
  354. unsigned char Len;
  355. unsigned long CRC;
  356. unsigned short Option;
  357. unsigned char AdapterAddress[MAC_LEN];
  358. };
  359. '''
  360. data += '\x02' # _tagDrcomAuthExtData.Code
  361. data += '\x0C' # _tagDrcomAuthExtData.Len
  362. data += checksum(data + '\x01\x26\x07\x11\x00\x00' + dump(mac)) # _tagDrcomAuthExtData.CRC
  363. data += '\x00\x00' # _tagDrcomAuthExtData.Option
  364. data += dump(mac) # _tagDrcomAuthExtData.AdapterAddress
  365. # END OF _tagDrcomAuthExtData
  366. if ror_version:
  367. data += '\x00' * (8 - len(pwd))
  368. if len(pwd)%2:
  369. data += '\x00'
  370. else:
  371. data += '\x00' # auto logout / default: False
  372. data += '\x00' # broadcast mode / default : False
  373. data += '\xE9\x13' #unknown, filled numbers randomly =w=
  374.  
  375. log('[mkpkt]',data.encode('hex'))
  376. return data
  377.  
  378. def login(usr, pwd, svr):
  379. global SALT
  380. global AUTH_INFO
  381.  
  382. i = 0
  383. timeoutcount = 0
  384. while True:
  385. salt = challenge(svr,time.time()+random.randint(0xF,0xFF))
  386. SALT = salt
  387. packet = mkpkt(salt, usr, pwd, mac)
  388. log('[login] send',packet.encode('hex'))
  389. s.sendto(packet, (svr, 61440))
  390. log('[login] packet sent.')
  391. try:
  392. data, address = s.recvfrom(1024)
  393. log('[login] recv',data.encode('hex'))
  394. if address == (svr, 61440) :
  395. if data[0] == '\x04':
  396. log('[login] loged in')
  397. AUTH_INFO = data[23:39]
  398. break
  399. else:
  400. log('[login] login failed.')
  401. if IS_TEST:
  402. time.sleep(3)
  403. else:
  404. time.sleep(30)
  405. continue
  406. else:
  407. if i >= 5 and UNLIMITED_RETRY == False :
  408. log('[login] exception occured.')
  409. sys.exit(1)
  410. else:
  411. i += 1
  412. continue
  413. except socket.timeout as e:
  414. print(e)
  415. log('[login] recv timeout.')
  416. timeoutcount += 1
  417. if timeoutcount >= 5:
  418. log('[login] recv timeout exception occured 5 times.')
  419. sys.exit(1)
  420. else:
  421. continue
  422.  
  423. log('[login] login sent')
  424. #0.8 changed:
  425. return data[23:39]
  426. #return data[-22:-6]
  427.  
  428. def logout(usr, pwd, svr, mac, auth_info):
  429. salt = challenge(svr, time.time()+random.randint(0xF, 0xFF))
  430. if salt:
  431. data = '\x06\x01\x00' + chr(len(usr) + 20)
  432. data += md5sum('\x03\x01' + salt + pwd)
  433. data += usr.ljust(36, '\x00')
  434. data += CONTROLCHECKSTATUS
  435. data += ADAPTERNUM
  436. data += dump(int(data[4:10].encode('hex'),16)^mac).rjust(6, '\x00')
  437. # data += '\x44\x72\x63\x6F' # Drco
  438. data += auth_info
  439. s.send(data)
  440. data, address = s.recvfrom(1024)
  441. if data[:1] == '\x04':
  442. log('[logout_auth] logouted.')
  443.  
  444. def keep_alive1(salt,tail,pwd,svr):
  445. foo = struct.pack('!H',int(time.time())%0xFFFF)
  446. data = '\xff' + md5sum('\x03\x01'+salt+pwd) + '\x00\x00\x00'
  447. data += tail
  448. data += foo + '\x00\x00\x00\x00'
  449. log('[keep_alive1] send',data.encode('hex'))
  450.  
  451. s.sendto(data, (svr, 61440))
  452. while True:
  453. try:
  454. data, address = s.recvfrom(1024)
  455. if data[0] == '\x07':
  456. break
  457. else:
  458. log('[keep-alive1]recv/not expected',data.encode('hex'))
  459. except:
  460. log('[keep_alive1] error', 'raise Exception to main() or keep_alive2()')
  461. raise
  462. log('[keep-alive1] recv',data.encode('hex'))
  463.  
  464. def empty_socket_buffer():
  465. #empty buffer for some fucking schools
  466. log('starting to empty socket buffer')
  467. try:
  468. while True:
  469. data, address = s.recvfrom(1024)
  470. log('recived sth unexpected',data.encode('hex'))
  471. if s == '':
  472. break
  473. except:
  474. # get exception means it has done.
  475. log('exception in empty_socket_buffer')
  476. pass
  477. log('emptyed')
  478. def daemon():
  479. with open('/var/run/jludrcom.pid','w') as f:
  480. f.write(str(os.getpid()))
  481.  
  482. def main():
  483. if not IS_TEST:
  484. daemon()
  485. execfile(CONF, globals())
  486. log("auth svr: " + server + "\nusername: " + username + "\npassword: " + password + "\nmac: " + str(hex(mac))[:-1])
  487. log("bind ip: " + bind_ip)
  488. while True:
  489. try:
  490. package_tail = login(username, password, server)
  491. except LoginException:
  492. continue
  493. log('package_tail',package_tail.encode('hex'))
  494. #keep_alive1 is fucking bullshit!
  495. empty_socket_buffer()
  496. try:
  497. keep_alive1(SALT,package_tail,password,server)
  498. keep_alive2(SALT,package_tail,password,server)
  499. except Exception as e:
  500. print(e)
  501. log('[main] error', 'something was wrong in keep_alives, do everything again')
  502. log(traceback.format_exc())
  503. time.sleep(3)
  504. #empty socket buffer before relogin
  505. empty_socket_buffer()
  506. continue
  507.  
  508. if __name__ == "__main__":
  509. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement