Kad atnÄcu strÄdÄt uz Å”o uzÅÄmumu, man jau bija kÄda IP ierÄ«Äu datubÄze, vairÄki serveri ar zvaigznÄ«ti un ielÄps FreeBPX formÄtÄ. TurklÄt analogais PBX Samsung IDCS500 strÄdÄja paralÄli un kopumÄ bija galvenÄ saziÅas sistÄma uzÅÄmumÄ; IP telefonija darbojÄs tikai pÄrdoÅ”anas nodaļÄ. Un viss bÅ«tu turpinÄjis gatavoties Å”Ädi, bet vienÄ jaukÄ dienÄ tika dots rÄ«kojums par visiem pÄrcelÅ”anu uz IP telefoniju, tika saskaÅoti termiÅi, iegÄdÄts aprÄ«kojums un sÄka Ä«stenot plÄnu uzÅÄmumu pÄrcelt uz 21. gadsimtu.
Pirmais, kas Å”ÄdÄ situÄcijÄ sÄk uztraukties, ir strauji augoÅ”ais telefona aparÄtu skaits, kas kaut kÄ jÄpÄrvalda, otrs, kas ļoti satrauca bija tÄlruÅu grÄmata. Ja Endpoint Manager varÄja mums palÄ«dzÄt ar pirmo (kas, starp citu, tika izgriezta no jaunÄkajÄm FreePBX versijÄm), tad saistÄ«bÄ ar grÄmatu radÄs daži jautÄjumi:
- PirmkÄrt, kÄ nodroÅ”inÄt tÄ precizitÄti, kad lietotÄju atraÅ”anÄs vieta/plÅ«stamÄ«ba nepÄrtraukti mainÄs?
- OtrkÄrt, kÄ pilnÄ«bÄ depersonalizÄt telefonus. Un katru reizi neierakstiet kontaktpersonas vÄrdu?
ProblÄma bija interesanta, nebija ilgi jÄgaida lÄ«dz risinÄjumam. Tagad es sniegÅ”u pilnu sarakstu, un tad mÄs to izskatÄ«sim secÄ«bÄ.
from scapy.all import sniff
from scapy.layers.inet import IP
import mysql.connector
import ldap
import getpass
import tftpy
import requests
import os
import time
from string import replace
def conn_ldap(login):
ad = ldap.initialize('ldap://***.local')
ad.simple_bind_s('voip@***.local', 'password')
basedn = 'OU=IT,DC=***,DC=LOCAL'
basedn_user = 'OU=***,OU=***,DC=***,DC=LOCAL'
scope = ldap.SCOPE_SUBTREE
filterexp = "(&(sAMAccountName=" + login + ")(ObjectClass=person))"
filterexp2 = "(&(ObjectClass=organizationUnit))"
attrlist = ['cn']
attrlist2 = ['OU']
search = ad.search_s(basedn, scope, filterexp, attrlist)
adname = search[0][1]['cn'][0].decode('utf-8')
if adname == ' ':
search = ad.search_s(basedn_user, scope, filterexp2, attrlist2)
for i in range(1, len(search)+1):
group = search[i][1]['ou'][0]
basedn_user2 = 'OU='+group+','+basedn_user
search = ad.search_s(basedn_user2, scope, filterexp, attrlist)
adname = search[0][1]['cn'][0].decode('utf-8')
if adname != ' ':
return adname
adname = search[0][1]['cn'][0].decode('utf-8')
ad.unbind_s()
return adname
def tftp_file_change(config,place,adname,current_account,current_account_password):
client = tftpy.TftpClient("192.168.0.3", 69)
client.download('template.cfg', place)
fileread = open(place, 'r')
line = fileread.readlines()
fileread.close()
line[5] = (('account.1.label = ').encode('utf-8') + adname.encode('utf-8') + 'n')
line[2] = (('account.1.auth_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
line[3] = (('account.1.display_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
line[6] = (('account.1.password = ').encode('utf-8') + current_account_password[0][0] + 'n')
filewrite = open(place, 'w')
for i in line:
filewrite.write(i)
filewrite.close()
print place
print config
client.upload(config,place)
def get_phone_inform(ipaddr):
fileconf = requests.get('http://admin:admin@'+ipaddr+'/servlet?phonecfg=get[&accounts=1]')
conf = fileconf.text.split('|')
current_account = conf[2]
return current_account
def sniff_frame():
pcapf = sniff(count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060")
if len(pcapf) == 0:
exit()
frame = pcapf[0]
macaddr = frame.src
print macaddr[:8]
if macaddr[:8] != '80:5e:c0':
exit()
ipaddr = frame[0][IP].src
return macaddr, ipaddr
def conn_mysql(query,fquery,macaddr,qwery2):
connect = mysql.connector.connect(host='192.168.0.3', database='voip', user='voip_wr', password='***')
cursor = connect.cursor()
cursor.execute(fquery)
state = cursor.fetchall()
state = bool(state[0][0])
if state == True:
cursor.execute(qwery2)
connect.commit()
connect.close()
else:
cursor.execute(query)
connect.commit()
connect.close()
def check_account(current_account):
connect = mysql.connector.connect(host='192.168.0.3', database='asterisk', user='voip_wr', password='***')
cursor = connect.cursor()
qwery = 'select data from sip where id=' + current_account + ' and keyword="secret";'
cursor.execute(qwery)
password = cursor.fetchall()
if password == ' ':
exit()
else:
return password
if __name__ == '__main__':
macaddr, ipaddr = sniff_frame()
current_account = get_phone_inform(ipaddr)
current_account_password = check_account(current_account)
macaddr = macaddr.replace(':', '')
ipaddr = ipaddr.decode('utf-8')
adname = conn_ldap(getpass.getuser())
query = 'INSERT INTO station (mac, ip, name, number) VALUES (' + '"' + macaddr + '",' + '"' + ipaddr + '",' + '"' + adname + '",' + '"' + get_phone_inform(ipaddr) + '"' + ')'
qwery2 = 'UPDATE station SET ip=' + '"' + ipaddr + '"' + ', name=' + '"' + adname + '"' + ', number=' + '"' + get_phone_inform(ipaddr) + '"' + ' WHERE mac=' + '"' + macaddr + '"'
fquery = 'SELECT EXISTS(SELECT mac FROM voip.station WHERE mac=' + '"' + macaddr + '")'
query = query.encode('utf-8')
fquery = fquery.encode('utf-8')
config = macaddr + '.cfg'
place = os.path.expanduser("~") + "" + "AppDataLocal" + config
conn_mysql(query,fquery,macaddr,qwery2)
tftp_file_change(config,place,adname,current_account,current_account_password)
requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=AutoP')
requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=Reboot')
Programma darbojas lietotÄja datorÄ un darbojas ar nosacÄ«jumu, ka dators ir savienots ar tÄ«klu, izmantojot tÄlruni, jo Yealink T19 nevar darboties kÄ vÄrteja.
PirmkÄrt, mums ir jÄsaprot, vai tas ir saistÄ«ts? un kÄds mac un ip ir mÅ«su telefonam.
def sniff_frame():
pcapf = sniff(count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060")
if len(pcapf) == 0:
exit()
frame = pcapf[0]
macaddr = frame.src
print macaddr[:8]
if macaddr[:8] != '80:5e:c0':
exit()
ipaddr = frame[0][IP].src
return macaddr, ipaddr
Å eit mÄs izmantojam funkciju sniff no scapy framework, ar tÄs palÄ«dzÄ«bu saÅemam iepriekÅ” noteiktu udp paketi, nogaidÄm 70 sekundes un, ja neko neÄ·eram, izejam.
count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060"
TÄlÄk mÄs pÄrliecinÄmies, ka ierÄ«ce patieÅ”Äm ir Yealink, un atgriežam nepiecieÅ”amÄs vÄrtÄ«bas (ip un mac).
Izmantojot Ä«paÅ”u pieprasÄ«jumu, noskaidrojam norÄÄ·inu kontu tÄlrunÄ«. Lai to izdarÄ«tu, paÅ”reizÄjÄ konfigurÄcija tiek lejupielÄdÄta no tÄlruÅa un parsÄta.
def get_phone_inform(ipaddr):
fileconf = requests.get('http://admin:admin@'+ipaddr+'/servlet?phonecfg=get[&accounts=1]')
conf = fileconf.text.split('|')
current_account = conf[2]
return current_account
Uzziniet Ŕī konta paroli. Lai to izdarÄ«tu, mÄs pievÄrÅ”amies tabulai asterisk.sip un tajÄ esoÅ”ajam datu laukam.
def check_account(current_account):
connect = mysql.connector.connect(host='192.168.0.3', database='asterisk', user='voip_wr', password='***')
cursor = connect.cursor()
qwery = 'select data from sip where id=' + current_account + ' and keyword="secret";'
cursor.execute(qwery)
password = cursor.fetchall()
if password == ' ':
exit()
else:
return password
Nu, pÄdÄjÄ posmÄ mÄs izveidojam savienojumu ar ldap AD un izmantojot funkciju sAMAccountName getpass.getuser() Åemiet paÅ”reizÄjÄ lietotÄja cn (kurÄ parasti ir pilns lietotÄja vÄrds).
def conn_ldap(login):
ad = ldap.initialize('ldap://***.local')
ad.simple_bind_s('voip@***.local', 'password')
basedn = 'OU=***,DC=***,DC=LOCAL'
basedn_user = 'OU=***,OU=***,DC=***,DC=LOCAL'
scope = ldap.SCOPE_SUBTREE
filterexp = "(&(sAMAccountName=" + login + ")(ObjectClass=person))"
filterexp2 = "(&(ObjectClass=organizationUnit))"
attrlist = ['cn']
attrlist2 = ['OU']
search = ad.search_s(basedn, scope, filterexp, attrlist)
adname = search[0][1]['cn'][0].decode('utf-8')
if adname == ' ':
search = ad.search_s(basedn_user, scope, filterexp2, attrlist2)
for i in range(1, len(search)+1):
group = search[i][1]['ou'][0]
basedn_user2 = 'OU='+group+','+basedn_user
search = ad.search_s(basedn_user2, scope, filterexp, attrlist)
adname = search[0][1]['cn'][0].decode('utf-8')
if adname != ' ':
return adname
adname = search[0][1]['cn'][0].decode('utf-8')
ad.unbind_s()
return adname
MÄs izveidojam savienojumu ar iepriekÅ” izveidotu tabulu datu bÄzÄ (es to izveidoju tur) un ievadÄm visu, ko uzzinÄjÄm, proti: ip, mac, lietotÄjvÄrds.
def conn_mysql(query,fquery,macaddr,qwery2):
connect = mysql.connector.connect(host='192.168.0.3', database='voip', user='voip_wr', password='***')
cursor = connect.cursor()
cursor.execute(fquery)
state = cursor.fetchall()
state = bool(state[0][0])
if state == True:
cursor.execute(qwery2)
connect.commit()
connect.close()
else:
cursor.execute(query)
connect.commit()
connect.close()
MÄs varÄtu apstÄties Å”eit, jo mÄs jau esam izveidojuÅ”i dinamisku adreÅ”u grÄmatu, jÅ«s varat jautÄt, bet es gÄju tÄlÄk un pievienoju Å”eit ierÄ«Äu automÄtisko nodroÅ”inÄÅ”anu.
Lai to izdarÄ«tu, no iepriekÅ” konfigurÄta tftp servera tiek lejupielÄdÄta veidnes konfigurÄcija, kurÄ mÄs veicam izmaiÅas un saglabÄjam to kÄ mac.cfg. Tas nozÄ«mÄ, ka Yealink ir divu veidu konfigurÄcijas, viens ir globÄls, bet otrs attiecas uz konkrÄtu tÄlruni, un tam jÄbÅ«t Å”ÄdÄ formÄtÄ: mac_phone.cfg.
PÄc visÄm izmaiÅÄm failÄ un tÄ saglabÄÅ”anas atpakaļ tftp serverÄ« mÄs dodam komandu tÄlrunim nodroÅ”inÄt un pÄrstartÄt ierÄ«ci.
def tftp_file_change(config,place,adname,current_account,current_account_password):
client = tftpy.TftpClient("192.168.0.3", 69)
client.download('template.cfg', place)
fileread = open(place, 'r')
line = fileread.readlines()
fileread.close()
line[5] = (('account.1.label = ').encode('utf-8') + adname.encode('utf-8') + 'n')
line[2] = (('account.1.auth_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
line[3] = (('account.1.display_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
line[6] = (('account.1.password = ').encode('utf-8') + current_account_password[0][0] + 'n')
filewrite = open(place, 'w')
for i in line:
filewrite.write(i)
filewrite.close()
print place
print config
client.upload(config,place)
requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=AutoP')
requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=Reboot')
PÄc ierÄ«ces pÄrstartÄÅ”anas telefona ekrÄnÄ tiek parÄdÄ«ts pilns vÄrds + vienmÄr pareizi aizpildÄ«ta adreÅ”u grÄmata datu bÄzes veidÄ, tad atliek tikai pievienot XML un nedaudz PHP, lai dinamiski parÄdÄ«tu saturu. TÄdu piemÄru ir daudz, pat YEALINK paÅ”am tÄdi ir.
P.S. Lai nodroÅ”inÄtu lielÄku mÄrogojamÄ«bu, galvenos iestatÄ«jumus (mainÄ«gos) varat ievietot atseviÅ”Ä·Ä failÄ.
Avots: www.habr.com