Soláthar uathoibríoch Yealink T19 + leabhar seoltaí dinimiciúil

Nuair a tháinig mé ag obair don chuideachta seo, bhí roinnt bunachar sonraí feistí IP agam cheana féin, roinnt freastalaithe le réiltín agus paiste i bhfoirm FreeBPX. Ina theannta sin, d'oibrigh analógach PBX Samsung IDCS500 ag an am céanna agus, go ginearálta, ba é an príomhchóras cumarsáide sa chuideachta; d'oibrigh teileafónaíocht IP don roinn díolacháin amháin. Agus bheadh ​​​​gach rud tar éis leanúint ar aghaidh ag cócaireacht mar seo, ach lá breá amháin tugadh foraithne chun gach duine a aistriú chuig teileafónaíocht IP, comhaontaíodh spriocdhátaí, ceannaíodh trealamh, agus cuireadh tús leis an bplean chun an fiontar a aistriú isteach sa 21ú haois a chur i bhfeidhm.
Is é an chéad rud a thosaíonn a bheith buartha i gcás den sórt sin ná an méadú tapa ar líon na dtacar teileafóin ar gá iad a bhainistiú ar bhealach éigin, ba é an dara rud a bhí an-imní ná an leabhar teileafóin. Más rud é go bhféadfadh Bainisteoir Endpoint cabhrú linn leis an gcéad cheann (a bhí, dála an scéil, gearrtha as na leaganacha is déanaí de FreePBX), tháinig roinnt ceisteanna chun cinn leis an leabhar:

  • Ar an gcéad dul síos, conas a chruinneas a chinntiú nuair a bhíonn suíomh/sreabhacht na n-úsáideoirí ag athrú de shíor?
  • Ar an dara dul síos, conas fóin a dhíphearsanú go hiomlán. Agus ní líon isteach an t-ainm teagmhála gach uair?

Bhí an fhadhb suimiúil, níor ghlac an réiteach i bhfad chun teacht. Anois tabharfaidh mé an liosta iomlán, agus ansin féachfaimid air in ord.

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')

Ritheann an clár ar ríomhaire an úsáideora agus oibríonn sé ar choinníoll go bhfuil an ríomhaire ceangailte leis an líonra trí ghuthán, toisc nach féidir le Yealink T19 oibriú mar gheata.

Gcéad dul síos, ní mór dúinn a thuiscint an bhfuil baint aige? agus cén mac agus ip atá ar ár nguthán.

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

Anseo bainimid úsáid as an bhfeidhm sniff ón gcreat scapy, lena chabhair a fhaigheann muid paicéad udp réamhshocraithe, fan 70 soicind agus mura nglacaimid rud ar bith, scoirimid.

count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060"

Next, déanaimid cinnte go bhfuil an gléas go deimhin Yealink agus ar ais na luachanna is gá (ip agus mac).

Ag baint úsáide as iarratas speisialta, faighimid amach an cuntas reatha ar an bhfón. Chun seo a dhéanamh, déantar an chumraíocht reatha a íoslódáil ón bhfón agus a pharsáil.

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

Faigh amach an pasfhocal don chuntas seo. Chun seo a dhéanamh, casaimid chuig an tábla asterisk.sip agus an réimse sonraí ann.

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

Bhuel, don chéim dheireanach nascann muid le ldap AD agus ag baint úsáide as sAMAccountName a fuarthas tríd an bhfeidhm getpass.getuser() tóg cn an úsáideora reatha (ina mbíonn ainm iomlán an úsáideora de ghnáth).

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

Ceanglaíonn muid le tábla réamhchruthaithe sa bhunachar sonraí (chruthaigh mé ann) agus cuirimid isteach gach rud a d'fhoghlaim muid, eadhon: ip, mac, ainm úsáideora.

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()

D’fhéadfaimis stop a chur anseo, toisc go bhfuil leabhar seoltaí dinimiciúil cruthaithe againn cheana féin, b’fhéidir go n-iarrfá, ach chuaigh mé níos faide agus chuir mé gléasanna ar fáil go huathoibríoch anseo.

Chun seo a dhéanamh, íoslódáiltear cumraíocht teimpléad ó fhreastalaí tftp réamh-chumraithe, ina ndéanaimid ár n-athruithe agus ina sábhálaimid é mar mac.cfg. Is é sin, le haghaidh Yealink tá dhá chineál cumraíochta ann, tá ceann amháin domhanda, agus baineann an dara ceann le fón ar leith agus ba cheart go mbeadh an fhoirm mac_phone.cfg

Tar éis na hathruithe go léir sa chomhad agus é a shábháil ar ais chuig an bhfreastalaí tftp, tugaimid an t-ordú chuig an bhfón chun an gléas a sholáthar agus a atosú.

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')

Tar éis an gléas a atosú, faigheann muid ár n-ainm iomlán ar scáileán an ghutháin + leabhar seoltaí atá líonta i gceart i gcónaí i bhfoirm bunachar sonraí, ansin níl le déanamh ach XML agus beagán PHP a chur leis chun an t-ábhar a thaispeáint go dinimiciúil. Tá go leor samplaí den sórt sin ann, fiú tá siad ag YEALINK féin.

PS: Ar mhaithe le hinscálaitheacht níos mó, is féidir leat na príomhshocruithe (athróga) a bhogadh isteach i gcomhad ar leith.

Foinse: will.com

Add a comment